2 The implementation of the ARP protocol.
4 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 // Global variable of EFI ARP Protocol Interface.
14 EFI_ARP_PROTOCOL mEfiArpProtocolTemplate
= {
25 Initialize the instance context data.
27 @param[in] ArpService Pointer to the arp service context data this
29 @param[out] Instance Pointer to the instance context data.
36 IN ARP_SERVICE_DATA
*ArpService
,
37 OUT ARP_INSTANCE_DATA
*Instance
40 NET_CHECK_SIGNATURE (ArpService
, ARP_SERVICE_DATA_SIGNATURE
);
42 Instance
->Signature
= ARP_INSTANCE_DATA_SIGNATURE
;
43 Instance
->ArpService
= ArpService
;
45 CopyMem (&Instance
->ArpProto
, &mEfiArpProtocolTemplate
, sizeof (Instance
->ArpProto
));
47 Instance
->Configured
= FALSE
;
48 Instance
->InDestroy
= FALSE
;
50 InitializeListHead (&Instance
->List
);
54 Process the Arp packets received from Mnp, the procedure conforms to RFC826.
56 @param[in] Context Pointer to the context data registered to the
69 ARP_SERVICE_DATA
*ArpService
;
70 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
71 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
73 ARP_ADDRESS ArpAddress
;
74 ARP_CACHE_ENTRY
*CacheEntry
;
76 ARP_INSTANCE_DATA
*Instance
;
77 EFI_ARP_CONFIG_DATA
*ConfigData
;
78 NET_ARP_ADDRESS SenderAddress
[2];
83 ArpService
= (ARP_SERVICE_DATA
*)Context
;
84 NET_CHECK_SIGNATURE (ArpService
, ARP_SERVICE_DATA_SIGNATURE
);
86 RxToken
= &ArpService
->RxToken
;
88 if (RxToken
->Status
== EFI_ABORTED
) {
90 // The Token is aborted, possibly by arp itself, just return and the receiving
91 // process is stopped.
96 if (EFI_ERROR (RxToken
->Status
)) {
98 // Restart the receiving if any other error Status occurs.
100 goto RESTART_RECEIVE
;
104 // Status is EFI_SUCCESS, process the received frame.
106 RxData
= RxToken
->Packet
.RxData
;
110 if (RxData
->DataLength
< sizeof (ARP_HEAD
)) {
112 // Restart the receiving if packet size is not correct.
118 // Convert the byte order of the multi-byte fields.
120 Head
= (ARP_HEAD
*)RxData
->PacketData
;
121 Head
->HwType
= NTOHS (Head
->HwType
);
122 Head
->ProtoType
= NTOHS (Head
->ProtoType
);
123 Head
->OpCode
= NTOHS (Head
->OpCode
);
125 if (RxData
->DataLength
< (sizeof (ARP_HEAD
) + 2 * Head
->HwAddrLen
+ 2 * Head
->ProtoAddrLen
)) {
129 if ((Head
->HwType
!= ArpService
->SnpMode
.IfType
) ||
130 (Head
->HwAddrLen
!= ArpService
->SnpMode
.HwAddressSize
) ||
131 (RxData
->ProtocolType
!= ARP_ETHER_PROTO_TYPE
))
134 // The hardware type or the hardware address length doesn't match.
135 // There is a sanity check for the protocol type too.
141 // Set the pointers to the addresses contained in the arp packet.
143 ArpAddress
.SenderHwAddr
= (UINT8
*)(Head
+ 1);
144 ArpAddress
.SenderProtoAddr
= ArpAddress
.SenderHwAddr
+ Head
->HwAddrLen
;
145 ArpAddress
.TargetHwAddr
= ArpAddress
.SenderProtoAddr
+ Head
->ProtoAddrLen
;
146 ArpAddress
.TargetProtoAddr
= ArpAddress
.TargetHwAddr
+ Head
->HwAddrLen
;
148 SenderAddress
[Hardware
].Type
= Head
->HwType
;
149 SenderAddress
[Hardware
].Length
= Head
->HwAddrLen
;
150 SenderAddress
[Hardware
].AddressPtr
= ArpAddress
.SenderHwAddr
;
152 SenderAddress
[Protocol
].Type
= Head
->ProtoType
;
153 SenderAddress
[Protocol
].Length
= Head
->ProtoAddrLen
;
154 SenderAddress
[Protocol
].AddressPtr
= ArpAddress
.SenderProtoAddr
;
157 // First, check the denied cache table.
159 CacheEntry
= ArpFindDeniedCacheEntry (
161 &SenderAddress
[Protocol
],
162 &SenderAddress
[Hardware
]
164 if (CacheEntry
!= NULL
) {
166 // This address (either hardware or protocol address, or both) is configured to
167 // be a deny entry, silently skip the normal process.
172 ProtoMatched
= FALSE
;
175 NET_LIST_FOR_EACH (Entry
, &ArpService
->ChildrenList
) {
177 // Iterate all the children.
179 Instance
= NET_LIST_USER_STRUCT (Entry
, ARP_INSTANCE_DATA
, List
);
180 NET_CHECK_SIGNATURE (Instance
, ARP_INSTANCE_DATA_SIGNATURE
);
181 ConfigData
= &Instance
->ConfigData
;
183 if ((Instance
->Configured
) &&
184 (Head
->ProtoType
== ConfigData
->SwAddressType
) &&
185 (Head
->ProtoAddrLen
== ConfigData
->SwAddressLength
))
188 // The protocol type is matched for the received arp packet.
191 if (0 == CompareMem (
192 (VOID
*)ArpAddress
.TargetProtoAddr
,
193 ConfigData
->StationAddress
,
194 ConfigData
->SwAddressLength
198 // The arp driver has the target address required by the received arp packet.
208 // Protocol type unmatchable, skip.
214 // Check whether the sender's address information is already in the cache.
217 CacheEntry
= ArpFindNextCacheEntryInTable (
218 &ArpService
->ResolvedCacheTable
,
221 &SenderAddress
[Protocol
],
224 if (CacheEntry
!= NULL
) {
226 // Update the entry with the new information.
228 ArpFillAddressInCacheEntry (CacheEntry
, &SenderAddress
[Hardware
], NULL
);
229 CacheEntry
->DecayTime
= CacheEntry
->DefaultDecayTime
;
235 // This arp packet isn't targeted to us, skip now.
242 // Add the triplet <protocol type, sender protocol address, sender hardware address>
243 // to the translation table.
245 CacheEntry
= ArpFindNextCacheEntryInTable (
246 &ArpService
->PendingRequestTable
,
249 &SenderAddress
[Protocol
],
252 if (CacheEntry
== NULL
) {
254 // Allocate a new CacheEntry.
256 CacheEntry
= ArpAllocCacheEntry (NULL
);
257 if (CacheEntry
== NULL
) {
262 if (!IsListEmpty (&CacheEntry
->List
)) {
263 RemoveEntryList (&CacheEntry
->List
);
267 // Fill the addresses into the CacheEntry.
269 ArpFillAddressInCacheEntry (
271 &SenderAddress
[Hardware
],
272 &SenderAddress
[Protocol
]
278 ArpAddressResolved (CacheEntry
, NULL
, NULL
);
281 // Add this entry into the ResolvedCacheTable
283 InsertHeadList (&ArpService
->ResolvedCacheTable
, &CacheEntry
->List
);
286 if (Head
->OpCode
== ARP_OPCODE_REQUEST
) {
288 // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
291 ArpSendFrame (Instance
, CacheEntry
, ARP_OPCODE_REPLY
);
297 // Signal Mnp to recycle the RxData.
299 gBS
->SignalEvent (RxData
->RecycleEvent
);
304 // Continue to receive packets from Mnp.
306 Status
= ArpService
->Mnp
->Receive (ArpService
->Mnp
, RxToken
);
309 if (EFI_ERROR (Status
)) {
312 "ArpOnFrameRcvd: ArpService->Mnp->Receive "
322 Queue ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK.
324 @param[in] Event The Event this notify function registered to.
325 @param[in] Context Pointer to the context data registered to the
339 // Request ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK
341 QueueDpc (TPL_CALLBACK
, ArpOnFrameRcvdDpc
, Context
);
345 Process the already sent arp packets.
347 @param[in] Context Pointer to the context data registered to the
359 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*TxToken
;
360 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
362 ASSERT (Context
!= NULL
);
364 TxToken
= (EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*)Context
;
365 TxData
= TxToken
->Packet
.TxData
;
368 if (EFI_ERROR (TxToken
->Status
)) {
369 DEBUG ((DEBUG_ERROR
, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken
->Status
));
375 // Free the allocated memory and close the event.
377 FreePool (TxData
->FragmentTable
[0].FragmentBuffer
);
379 gBS
->CloseEvent (TxToken
->Event
);
384 Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.
386 @param[in] Event The Event this notify function registered to.
387 @param[in] Context Pointer to the context data registered to the
401 // Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK
403 QueueDpc (TPL_CALLBACK
, ArpOnFrameSentDpc
, Context
);
407 Process the arp cache olding and drive the retrying arp requests.
409 @param[in] Event The Event this notify function registered to.
410 @param[in] Context Pointer to the context data registered to the
423 ARP_SERVICE_DATA
*ArpService
;
425 LIST_ENTRY
*NextEntry
;
426 LIST_ENTRY
*ContextEntry
;
427 ARP_CACHE_ENTRY
*CacheEntry
;
428 USER_REQUEST_CONTEXT
*RequestContext
;
430 ASSERT (Context
!= NULL
);
431 ArpService
= (ARP_SERVICE_DATA
*)Context
;
434 // Iterate all the pending requests to see whether a retry is needed to send out
435 // or the request finally fails because the retry time reaches the limitation.
437 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &ArpService
->PendingRequestTable
) {
438 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
440 if (CacheEntry
->NextRetryTime
<= ARP_PERIODIC_TIMER_INTERVAL
) {
442 // Timeout, if we can retry more, send out the request again, otherwise abort
445 if (CacheEntry
->RetryCount
== 0) {
447 // Abort this request.
449 ArpAddressResolved (CacheEntry
, NULL
, NULL
);
450 ASSERT (IsListEmpty (&CacheEntry
->UserRequestList
));
452 RemoveEntryList (&CacheEntry
->List
);
453 FreePool (CacheEntry
);
456 // resend the ARP request.
458 ASSERT (!IsListEmpty (&CacheEntry
->UserRequestList
));
460 ContextEntry
= CacheEntry
->UserRequestList
.ForwardLink
;
461 RequestContext
= NET_LIST_USER_STRUCT (ContextEntry
, USER_REQUEST_CONTEXT
, List
);
463 ArpSendFrame (RequestContext
->Instance
, CacheEntry
, ARP_OPCODE_REQUEST
);
465 CacheEntry
->RetryCount
--;
466 CacheEntry
->NextRetryTime
= RequestContext
->Instance
->ConfigData
.RetryTimeOut
;
470 // Update the NextRetryTime.
472 CacheEntry
->NextRetryTime
-= ARP_PERIODIC_TIMER_INTERVAL
;
477 // Check the timeouts for the DeniedCacheTable.
479 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &ArpService
->DeniedCacheTable
) {
480 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
481 ASSERT (IsListEmpty (&CacheEntry
->UserRequestList
));
483 if (CacheEntry
->DefaultDecayTime
== 0) {
485 // It's a static entry, skip it.
490 if (CacheEntry
->DecayTime
<= ARP_PERIODIC_TIMER_INTERVAL
) {
492 // Time out, remove it.
494 RemoveEntryList (&CacheEntry
->List
);
495 FreePool (CacheEntry
);
498 // Update the DecayTime.
500 CacheEntry
->DecayTime
-= ARP_PERIODIC_TIMER_INTERVAL
;
505 // Check the timeouts for the ResolvedCacheTable.
507 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &ArpService
->ResolvedCacheTable
) {
508 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
509 ASSERT (IsListEmpty (&CacheEntry
->UserRequestList
));
511 if (CacheEntry
->DefaultDecayTime
== 0) {
513 // It's a static entry, skip it.
518 if (CacheEntry
->DecayTime
<= ARP_PERIODIC_TIMER_INTERVAL
) {
520 // Time out, remove it.
522 RemoveEntryList (&CacheEntry
->List
);
523 FreePool (CacheEntry
);
526 // Update the DecayTime.
528 CacheEntry
->DecayTime
-= ARP_PERIODIC_TIMER_INTERVAL
;
534 Match the two NET_ARP_ADDRESSes.
536 @param[in] AddressOne Pointer to the first address to match.
537 @param[in] AddressTwo Pointer to the second address to match.
539 @return The two addresses match or not.
544 IN NET_ARP_ADDRESS
*AddressOne
,
545 IN NET_ARP_ADDRESS
*AddressTwo
548 ASSERT (AddressOne
!= NULL
&& AddressTwo
!= NULL
);
550 if ((AddressOne
->Type
!= AddressTwo
->Type
) ||
551 (AddressOne
->Length
!= AddressTwo
->Length
))
554 // Either Type or Length doesn't match.
559 if ((AddressOne
->AddressPtr
!= NULL
) &&
561 AddressOne
->AddressPtr
,
562 AddressTwo
->AddressPtr
,
567 // The address is not the same.
576 Find the CacheEntry which matches the requirements in the specified CacheTable.
578 @param[in] CacheTable Pointer to the arp cache table.
579 @param[in] StartEntry Pointer to the start entry this search begins with
581 @param[in] FindOpType The search type.
582 @param[in] ProtocolAddress Pointer to the protocol address to match.
583 @param[in] HardwareAddress Pointer to the hardware address to match.
585 @return Pointer to the matched arp cache entry, if NULL, no match is found.
589 ArpFindNextCacheEntryInTable (
590 IN LIST_ENTRY
*CacheTable
,
591 IN LIST_ENTRY
*StartEntry
,
592 IN FIND_OPTYPE FindOpType
,
593 IN NET_ARP_ADDRESS
*ProtocolAddress OPTIONAL
,
594 IN NET_ARP_ADDRESS
*HardwareAddress OPTIONAL
598 ARP_CACHE_ENTRY
*CacheEntry
;
600 if (StartEntry
== NULL
) {
602 // Start from the beginning of the table if no StartEntry is specified.
604 StartEntry
= CacheTable
;
607 for (Entry
= StartEntry
->ForwardLink
; Entry
!= CacheTable
; Entry
= Entry
->ForwardLink
) {
608 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
610 if ((FindOpType
& MATCH_SW_ADDRESS
) != 0) {
612 // Find by the software address.
614 if (!ArpMatchAddress (ProtocolAddress
, &CacheEntry
->Addresses
[Protocol
])) {
616 // The ProtocolAddress doesn't match, continue to the next cache entry.
622 if ((FindOpType
& MATCH_HW_ADDRESS
) != 0) {
624 // Find by the hardware address.
626 if (!ArpMatchAddress (HardwareAddress
, &CacheEntry
->Addresses
[Hardware
])) {
628 // The HardwareAddress doesn't match, continue to the next cache entry.
635 // The CacheEntry meets the requirements now, return this entry.
647 Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
648 in the DeniedCacheTable.
650 @param[in] ArpService Pointer to the arp service context data.
651 @param[in] ProtocolAddress Pointer to the protocol address.
652 @param[in] HardwareAddress Pointer to the hardware address.
654 @return Pointer to the matched cache entry, if NULL no match is found.
658 ArpFindDeniedCacheEntry (
659 IN ARP_SERVICE_DATA
*ArpService
,
660 IN NET_ARP_ADDRESS
*ProtocolAddress OPTIONAL
,
661 IN NET_ARP_ADDRESS
*HardwareAddress OPTIONAL
664 ARP_CACHE_ENTRY
*CacheEntry
;
666 ASSERT ((ProtocolAddress
!= NULL
) || (HardwareAddress
!= NULL
));
667 NET_CHECK_SIGNATURE (ArpService
, ARP_SERVICE_DATA_SIGNATURE
);
671 if ((ProtocolAddress
!= NULL
) && (ProtocolAddress
->AddressPtr
!= NULL
)) {
673 // Find the cache entry in the DeniedCacheTable by the protocol address.
675 CacheEntry
= ArpFindNextCacheEntryInTable (
676 &ArpService
->DeniedCacheTable
,
682 if (CacheEntry
!= NULL
) {
690 if ((HardwareAddress
!= NULL
) && (HardwareAddress
->AddressPtr
!= NULL
)) {
692 // Find the cache entry in the DeniedCacheTable by the hardware address.
694 CacheEntry
= ArpFindNextCacheEntryInTable (
695 &ArpService
->DeniedCacheTable
,
707 Allocate a cache entry and initialize it.
709 @param[in] Instance Pointer to the instance context data.
711 @return Pointer to the new created cache entry.
716 IN ARP_INSTANCE_DATA
*Instance
719 ARP_CACHE_ENTRY
*CacheEntry
;
720 NET_ARP_ADDRESS
*Address
;
724 // Allocate memory for the cache entry.
726 CacheEntry
= AllocatePool (sizeof (ARP_CACHE_ENTRY
));
727 if (CacheEntry
== NULL
) {
734 InitializeListHead (&CacheEntry
->List
);
735 InitializeListHead (&CacheEntry
->UserRequestList
);
737 for (Index
= 0; Index
< 2; Index
++) {
739 // Init the address pointers to point to the concrete buffer.
741 Address
= &CacheEntry
->Addresses
[Index
];
742 Address
->AddressPtr
= Address
->Buffer
.ProtoAddress
;
746 // Zero the hardware address first.
748 ZeroMem (CacheEntry
->Addresses
[Hardware
].AddressPtr
, ARP_MAX_HARDWARE_ADDRESS_LEN
);
750 if (Instance
!= NULL
) {
752 // Inherit the parameters from the instance configuration.
754 CacheEntry
->RetryCount
= Instance
->ConfigData
.RetryCount
;
755 CacheEntry
->NextRetryTime
= Instance
->ConfigData
.RetryTimeOut
;
756 CacheEntry
->DefaultDecayTime
= Instance
->ConfigData
.EntryTimeOut
;
757 CacheEntry
->DecayTime
= Instance
->ConfigData
.EntryTimeOut
;
760 // Use the default parameters if this cache entry isn't allocate in a
763 CacheEntry
->RetryCount
= ARP_DEFAULT_RETRY_COUNT
;
764 CacheEntry
->NextRetryTime
= ARP_DEFAULT_RETRY_INTERVAL
;
765 CacheEntry
->DefaultDecayTime
= ARP_DEFAULT_TIMEOUT_VALUE
;
766 CacheEntry
->DecayTime
= ARP_DEFAULT_TIMEOUT_VALUE
;
773 Turn the CacheEntry into the resolved status.
775 @param[in] CacheEntry Pointer to the resolved cache entry.
776 @param[in] Instance Pointer to the instance context data.
777 @param[in] UserEvent Pointer to the UserEvent to notify.
779 @return The count of notifications sent to the instance.
784 IN ARP_CACHE_ENTRY
*CacheEntry
,
785 IN ARP_INSTANCE_DATA
*Instance OPTIONAL
,
786 IN EFI_EVENT UserEvent OPTIONAL
790 LIST_ENTRY
*NextEntry
;
791 USER_REQUEST_CONTEXT
*Context
;
797 // Iterate all the linked user requests to notify them.
799 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &CacheEntry
->UserRequestList
) {
800 Context
= NET_LIST_USER_STRUCT (Entry
, USER_REQUEST_CONTEXT
, List
);
802 if (((Instance
== NULL
) || (Context
->Instance
== Instance
)) &&
803 ((UserEvent
== NULL
) || (Context
->UserRequestEvent
== UserEvent
)))
806 // Copy the address to the user-provided buffer and notify the user.
809 Context
->UserHwAddrBuffer
,
810 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
811 CacheEntry
->Addresses
[Hardware
].Length
813 gBS
->SignalEvent (Context
->UserRequestEvent
);
816 // Remove this user request and free the context data.
818 RemoveEntryList (&Context
->List
);
826 // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.
834 Fill the addresses in the CacheEntry using the information passed in by
837 @param[in] CacheEntry Pointer to the cache entry.
838 @param[in] HwAddr Pointer to the software address.
839 @param[in] SwAddr Pointer to the hardware address.
845 ArpFillAddressInCacheEntry (
846 IN ARP_CACHE_ENTRY
*CacheEntry
,
847 IN NET_ARP_ADDRESS
*HwAddr OPTIONAL
,
848 IN NET_ARP_ADDRESS
*SwAddr OPTIONAL
851 NET_ARP_ADDRESS
*Address
[2];
852 NET_ARP_ADDRESS
*CacheAddress
;
855 Address
[Hardware
] = HwAddr
;
856 Address
[Protocol
] = SwAddr
;
858 for (Index
= 0; Index
< 2; Index
++) {
859 if (Address
[Index
] != NULL
) {
861 // Fill the address if the passed in pointer is not NULL.
863 CacheAddress
= &CacheEntry
->Addresses
[Index
];
865 CacheAddress
->Type
= Address
[Index
]->Type
;
866 CacheAddress
->Length
= Address
[Index
]->Length
;
868 if (Address
[Index
]->AddressPtr
!= NULL
) {
870 // Copy it if the AddressPtr points to some buffer.
873 CacheAddress
->AddressPtr
,
874 Address
[Index
]->AddressPtr
,
879 // Zero the corresponding address buffer in the CacheEntry.
881 ZeroMem (CacheAddress
->AddressPtr
, CacheAddress
->Length
);
888 Configure the instance using the ConfigData. ConfigData is already validated.
890 @param[in] Instance Pointer to the instance context data to be
892 @param[in] ConfigData Pointer to the configuration data used to
893 configure the instance.
895 @retval EFI_SUCCESS The instance is configured with the ConfigData.
896 @retval EFI_ACCESS_DENIED The instance is already configured and the
897 ConfigData tries to reset some unchangeable
899 @retval EFI_INVALID_PARAMETER The ConfigData provides a non-unicast IPv4 address
900 when the SwAddressType is IPv4.
901 @retval EFI_OUT_OF_RESOURCES The instance fails to configure due to memory
906 ArpConfigureInstance (
907 IN ARP_INSTANCE_DATA
*Instance
,
908 IN EFI_ARP_CONFIG_DATA
*ConfigData OPTIONAL
911 EFI_ARP_CONFIG_DATA
*OldConfigData
;
914 OldConfigData
= &Instance
->ConfigData
;
916 if (ConfigData
!= NULL
) {
917 if (Instance
->Configured
) {
919 // The instance is configured, check the unchangeable fields.
921 if ((OldConfigData
->SwAddressType
!= ConfigData
->SwAddressType
) ||
922 (OldConfigData
->SwAddressLength
!= ConfigData
->SwAddressLength
) ||
924 OldConfigData
->StationAddress
,
925 ConfigData
->StationAddress
,
926 OldConfigData
->SwAddressLength
930 // Deny the unallowed changes.
932 return EFI_ACCESS_DENIED
;
936 // The instance is not configured.
939 if (ConfigData
->SwAddressType
== IPV4_ETHER_PROTO_TYPE
) {
940 CopyMem (&Ip
, ConfigData
->StationAddress
, sizeof (IP4_ADDR
));
942 if (IP4_IS_UNSPECIFIED (Ip
) || IP4_IS_LOCAL_BROADCAST (Ip
)) {
944 // The station address should not be zero or broadcast address.
946 return EFI_INVALID_PARAMETER
;
951 // Save the configuration.
953 CopyMem (OldConfigData
, ConfigData
, sizeof (*OldConfigData
));
955 OldConfigData
->StationAddress
= AllocatePool (OldConfigData
->SwAddressLength
);
956 if (OldConfigData
->StationAddress
== NULL
) {
959 "ArpConfigInstance: AllocatePool for the StationAddress "
962 return EFI_OUT_OF_RESOURCES
;
966 // Save the StationAddress.
969 OldConfigData
->StationAddress
,
970 ConfigData
->StationAddress
,
971 OldConfigData
->SwAddressLength
975 // Set the state to configured.
977 Instance
->Configured
= TRUE
;
981 // Use the implementation specific values if the following field is zero.
983 OldConfigData
->EntryTimeOut
= (ConfigData
->EntryTimeOut
== 0) ?
984 ARP_DEFAULT_TIMEOUT_VALUE
: ConfigData
->EntryTimeOut
;
986 OldConfigData
->RetryCount
= (ConfigData
->RetryCount
== 0) ?
987 ARP_DEFAULT_RETRY_COUNT
: ConfigData
->RetryCount
;
989 OldConfigData
->RetryTimeOut
= (ConfigData
->RetryTimeOut
== 0) ?
990 ARP_DEFAULT_RETRY_INTERVAL
: ConfigData
->RetryTimeOut
;
993 // Reset the configuration.
996 if (Instance
->Configured
) {
998 // Cancel the arp requests issued by this instance.
1000 Instance
->ArpProto
.Cancel (&Instance
->ArpProto
, NULL
, NULL
);
1003 // Free the buffer previously allocated to hold the station address.
1005 FreePool (OldConfigData
->StationAddress
);
1008 Instance
->Configured
= FALSE
;
1015 Send out an arp frame using the CacheEntry and the ArpOpCode.
1017 @param[in] Instance Pointer to the instance context data.
1018 @param[in] CacheEntry Pointer to the configuration data used to
1019 configure the instance.
1020 @param[in] ArpOpCode The opcode used to send out this Arp frame, either
1028 IN ARP_INSTANCE_DATA
*Instance
,
1029 IN ARP_CACHE_ENTRY
*CacheEntry
,
1034 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*TxToken
;
1035 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
1038 ARP_SERVICE_DATA
*ArpService
;
1039 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
1040 EFI_ARP_CONFIG_DATA
*ConfigData
;
1044 ASSERT ((Instance
!= NULL
) && (CacheEntry
!= NULL
));
1047 // Allocate memory for the TxToken.
1049 TxToken
= AllocatePool (sizeof (EFI_MANAGED_NETWORK_COMPLETION_TOKEN
));
1050 if (TxToken
== NULL
) {
1051 DEBUG ((DEBUG_ERROR
, "ArpSendFrame: Allocate memory for TxToken failed.\n"));
1055 TxToken
->Event
= NULL
;
1060 // Create the event for this TxToken.
1062 Status
= gBS
->CreateEvent (
1069 if (EFI_ERROR (Status
)) {
1070 DEBUG ((DEBUG_ERROR
, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
1075 // Allocate memory for the TxData used in the TxToken.
1077 TxData
= AllocatePool (sizeof (EFI_MANAGED_NETWORK_TRANSMIT_DATA
));
1078 if (TxData
== NULL
) {
1079 DEBUG ((DEBUG_ERROR
, "ArpSendFrame: Allocate memory for TxData failed.\n"));
1083 ArpService
= Instance
->ArpService
;
1084 SnpMode
= &ArpService
->SnpMode
;
1085 ConfigData
= &Instance
->ConfigData
;
1088 // Calculate the buffer length for this arp frame.
1090 TotalLength
= SnpMode
->MediaHeaderSize
+ sizeof (ARP_HEAD
) +
1091 2 * (ConfigData
->SwAddressLength
+ SnpMode
->HwAddressSize
);
1094 // Allocate buffer for the arp frame.
1096 Packet
= AllocatePool (TotalLength
);
1097 if (Packet
== NULL
) {
1098 DEBUG ((DEBUG_ERROR
, "ArpSendFrame: Allocate memory for Packet failed.\n"));
1099 ASSERT (Packet
!= NULL
);
1105 // The destination MAC address.
1107 if (ArpOpCode
== ARP_OPCODE_REQUEST
) {
1108 CopyMem (TmpPtr
, &SnpMode
->BroadcastAddress
, SnpMode
->HwAddressSize
);
1112 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1113 SnpMode
->HwAddressSize
1117 TmpPtr
+= SnpMode
->HwAddressSize
;
1120 // The source MAC address.
1122 CopyMem (TmpPtr
, &SnpMode
->CurrentAddress
, SnpMode
->HwAddressSize
);
1123 TmpPtr
+= SnpMode
->HwAddressSize
;
1126 // The ethernet protocol type.
1128 *(UINT16
*)TmpPtr
= HTONS (ARP_ETHER_PROTO_TYPE
);
1134 ArpHead
= (ARP_HEAD
*)TmpPtr
;
1135 ArpHead
->HwType
= HTONS ((UINT16
)SnpMode
->IfType
);
1136 ArpHead
->ProtoType
= HTONS (ConfigData
->SwAddressType
);
1137 ArpHead
->HwAddrLen
= (UINT8
)SnpMode
->HwAddressSize
;
1138 ArpHead
->ProtoAddrLen
= ConfigData
->SwAddressLength
;
1139 ArpHead
->OpCode
= HTONS (ArpOpCode
);
1140 TmpPtr
+= sizeof (ARP_HEAD
);
1143 // The sender hardware address.
1145 CopyMem (TmpPtr
, &SnpMode
->CurrentAddress
, SnpMode
->HwAddressSize
);
1146 TmpPtr
+= SnpMode
->HwAddressSize
;
1149 // The sender protocol address.
1151 CopyMem (TmpPtr
, ConfigData
->StationAddress
, ConfigData
->SwAddressLength
);
1152 TmpPtr
+= ConfigData
->SwAddressLength
;
1155 // The target hardware address.
1159 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1160 SnpMode
->HwAddressSize
1162 TmpPtr
+= SnpMode
->HwAddressSize
;
1165 // The target protocol address.
1169 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1170 ConfigData
->SwAddressLength
1174 // Set all the fields of the TxData.
1176 TxData
->DestinationAddress
= NULL
;
1177 TxData
->SourceAddress
= NULL
;
1178 TxData
->ProtocolType
= 0;
1179 TxData
->DataLength
= TotalLength
- SnpMode
->MediaHeaderSize
;
1180 TxData
->HeaderLength
= (UINT16
)SnpMode
->MediaHeaderSize
;
1181 TxData
->FragmentCount
= 1;
1183 TxData
->FragmentTable
[0].FragmentBuffer
= Packet
;
1184 TxData
->FragmentTable
[0].FragmentLength
= TotalLength
;
1187 // Associate the TxData with the TxToken.
1189 TxToken
->Packet
.TxData
= TxData
;
1190 TxToken
->Status
= EFI_NOT_READY
;
1193 // Send out this arp packet by Mnp.
1195 Status
= ArpService
->Mnp
->Transmit (ArpService
->Mnp
, TxToken
);
1196 if (EFI_ERROR (Status
)) {
1197 DEBUG ((DEBUG_ERROR
, "Mnp->Transmit failed, %r.\n", Status
));
1205 if (Packet
!= NULL
) {
1209 if (TxData
!= NULL
) {
1213 if (TxToken
->Event
!= NULL
) {
1214 gBS
->CloseEvent (TxToken
->Event
);
1221 Delete the cache entries in the specified CacheTable, using the BySwAddress,
1222 SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,
1223 the cache is deleted event it's a static entry.
1225 @param[in] CacheTable Pointer to the cache table to do the deletion.
1226 @param[in] BySwAddress Delete the cache entry by software address or by
1228 @param[in] SwAddressType The software address used to do the deletion.
1229 @param[in] AddressBuffer Pointer to the buffer containing the address to
1230 match for the deletion.
1231 @param[in] Force This deletion is forced or not.
1233 @return The count of the deleted cache entries.
1237 ArpDeleteCacheEntryInTable (
1238 IN LIST_ENTRY
*CacheTable
,
1239 IN BOOLEAN BySwAddress
,
1240 IN UINT16 SwAddressType
,
1241 IN UINT8
*AddressBuffer OPTIONAL
,
1246 LIST_ENTRY
*NextEntry
;
1247 ARP_CACHE_ENTRY
*CacheEntry
;
1252 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, CacheTable
) {
1253 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
1255 if ((CacheEntry
->DefaultDecayTime
== 0) && !Force
) {
1257 // It's a static entry and we are not forced to delete it, skip.
1263 if (SwAddressType
== CacheEntry
->Addresses
[Protocol
].Type
) {
1265 // Protocol address type matched. Check the address.
1267 if ((AddressBuffer
== NULL
) ||
1270 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1271 CacheEntry
->Addresses
[Protocol
].Length
1281 if ((AddressBuffer
== NULL
) ||
1284 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1285 CacheEntry
->Addresses
[Hardware
].Length
1300 // Delete this entry.
1302 RemoveEntryList (&CacheEntry
->List
);
1303 ASSERT (IsListEmpty (&CacheEntry
->UserRequestList
));
1304 FreePool (CacheEntry
);
1313 Delete cache entries in all the cache tables.
1315 @param[in] Instance Pointer to the instance context data.
1316 @param[in] BySwAddress Delete the cache entry by software address or by
1318 @param[in] AddressBuffer Pointer to the buffer containing the address to
1319 match for the deletion.
1320 @param[in] Force This deletion is forced or not.
1322 @return The count of the deleted cache entries.
1326 ArpDeleteCacheEntry (
1327 IN ARP_INSTANCE_DATA
*Instance
,
1328 IN BOOLEAN BySwAddress
,
1329 IN UINT8
*AddressBuffer OPTIONAL
,
1333 ARP_SERVICE_DATA
*ArpService
;
1336 NET_CHECK_SIGNATURE (Instance
, ARP_INSTANCE_DATA_SIGNATURE
);
1338 ArpService
= Instance
->ArpService
;
1341 // Delete the cache entries in the DeniedCacheTable.
1343 Count
= ArpDeleteCacheEntryInTable (
1344 &ArpService
->DeniedCacheTable
,
1346 Instance
->ConfigData
.SwAddressType
,
1352 // Delete the cache entries in the ResolvedCacheTable.
1354 Count
+= ArpDeleteCacheEntryInTable (
1355 &ArpService
->ResolvedCacheTable
,
1357 Instance
->ConfigData
.SwAddressType
,
1366 Cancel the arp request.
1368 @param[in] Instance Pointer to the instance context data.
1369 @param[in] TargetSwAddress Pointer to the buffer containing the target
1370 software address to match the arp request.
1371 @param[in] UserEvent The user event used to notify this request
1374 @return The count of the cancelled requests.
1379 IN ARP_INSTANCE_DATA
*Instance
,
1380 IN VOID
*TargetSwAddress OPTIONAL
,
1381 IN EFI_EVENT UserEvent OPTIONAL
1384 ARP_SERVICE_DATA
*ArpService
;
1386 LIST_ENTRY
*NextEntry
;
1387 ARP_CACHE_ENTRY
*CacheEntry
;
1390 NET_CHECK_SIGNATURE (Instance
, ARP_INSTANCE_DATA_SIGNATURE
);
1392 ArpService
= Instance
->ArpService
;
1395 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &ArpService
->PendingRequestTable
) {
1396 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
1398 if ((TargetSwAddress
== NULL
) ||
1401 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1402 CacheEntry
->Addresses
[Protocol
].Length
1406 // This request entry matches the TargetSwAddress or all requests are to be
1407 // cancelled as TargetSwAddress is NULL.
1409 Count
+= ArpAddressResolved (CacheEntry
, Instance
, UserEvent
);
1411 if (IsListEmpty (&CacheEntry
->UserRequestList
)) {
1413 // No user requests any more, remove this request cache entry.
1415 RemoveEntryList (&CacheEntry
->List
);
1416 FreePool (CacheEntry
);
1425 Find the cache entry in the cache table.
1427 @param[in] Instance Pointer to the instance context data.
1428 @param[in] BySwAddress Set to TRUE to look for matching software protocol
1429 addresses. Set to FALSE to look for matching
1430 hardware protocol addresses.
1431 @param[in] AddressBuffer Pointer to address buffer. Set to NULL to match
1433 @param[out] EntryLength The size of an entry in the entries buffer.
1434 @param[out] EntryCount The number of ARP cache entries that are found by
1435 the specified criteria.
1436 @param[out] Entries Pointer to the buffer that will receive the ARP
1438 @param[in] Refresh Set to TRUE to refresh the timeout value of the
1439 matching ARP cache entry.
1441 @retval EFI_SUCCESS The requested ARP cache entries are copied into
1443 @retval EFI_NOT_FOUND No matching entries found.
1444 @retval EFI_OUT_OF_RESOURCE There is a memory allocation failure.
1449 IN ARP_INSTANCE_DATA
*Instance
,
1450 IN BOOLEAN BySwAddress
,
1451 IN VOID
*AddressBuffer OPTIONAL
,
1452 OUT UINT32
*EntryLength OPTIONAL
,
1453 OUT UINT32
*EntryCount OPTIONAL
,
1454 OUT EFI_ARP_FIND_DATA
**Entries OPTIONAL
,
1459 ARP_SERVICE_DATA
*ArpService
;
1460 NET_ARP_ADDRESS MatchAddress
;
1461 FIND_OPTYPE FindOpType
;
1462 LIST_ENTRY
*StartEntry
;
1463 ARP_CACHE_ENTRY
*CacheEntry
;
1464 NET_MAP FoundEntries
;
1466 EFI_ARP_FIND_DATA
*FindData
;
1467 LIST_ENTRY
*CacheTable
;
1468 UINT32 FoundEntryLength
;
1470 ArpService
= Instance
->ArpService
;
1473 // Init the FoundEntries used to hold the found cache entries.
1475 NetMapInit (&FoundEntries
);
1478 // Set the MatchAddress.
1481 MatchAddress
.Type
= Instance
->ConfigData
.SwAddressType
;
1482 MatchAddress
.Length
= Instance
->ConfigData
.SwAddressLength
;
1483 FindOpType
= ByProtoAddress
;
1485 MatchAddress
.Type
= ArpService
->SnpMode
.IfType
;
1486 MatchAddress
.Length
= (UINT8
)ArpService
->SnpMode
.HwAddressSize
;
1487 FindOpType
= ByHwAddress
;
1490 MatchAddress
.AddressPtr
= AddressBuffer
;
1493 // Search the DeniedCacheTable
1498 // Try to find the matched entries in the DeniedCacheTable.
1500 CacheEntry
= ArpFindNextCacheEntryInTable (
1501 &ArpService
->DeniedCacheTable
,
1507 if (CacheEntry
== NULL
) {
1509 // Once the CacheEntry is NULL, there are no more matches.
1515 // Insert the found entry into the map.
1520 (VOID
*)&ArpService
->DeniedCacheTable
1524 // Let the next search start from this cache entry.
1526 StartEntry
= &CacheEntry
->List
;
1530 // Refresh the DecayTime if needed.
1532 CacheEntry
->DecayTime
= CacheEntry
->DefaultDecayTime
;
1537 // Search the ResolvedCacheTable
1541 CacheEntry
= ArpFindNextCacheEntryInTable (
1542 &ArpService
->ResolvedCacheTable
,
1548 if (CacheEntry
== NULL
) {
1550 // Once the CacheEntry is NULL, there are no more matches.
1556 // Insert the found entry into the map.
1561 (VOID
*)&ArpService
->ResolvedCacheTable
1565 // Let the next search start from this cache entry.
1567 StartEntry
= &CacheEntry
->List
;
1571 // Refresh the DecayTime if needed.
1573 CacheEntry
->DecayTime
= CacheEntry
->DefaultDecayTime
;
1577 Status
= EFI_SUCCESS
;
1579 FoundCount
= (UINT32
)NetMapGetCount (&FoundEntries
);
1580 if (FoundCount
== 0) {
1581 Status
= EFI_NOT_FOUND
;
1586 // Found the entry length, make sure its 8 bytes alignment.
1588 FoundEntryLength
= (((sizeof (EFI_ARP_FIND_DATA
) + Instance
->ConfigData
.SwAddressLength
+
1589 ArpService
->SnpMode
.HwAddressSize
) + 3) & ~(0x3));
1591 if (EntryLength
!= NULL
) {
1592 *EntryLength
= FoundEntryLength
;
1595 if (EntryCount
!= NULL
) {
1597 // Return the found entry count.
1599 *EntryCount
= FoundCount
;
1602 if (Entries
== NULL
) {
1607 // Allocate buffer to copy the found entries.
1609 FindData
= AllocatePool (FoundCount
* FoundEntryLength
);
1610 if (FindData
== NULL
) {
1611 DEBUG ((DEBUG_ERROR
, "ArpFindCacheEntry: Failed to allocate memory.\n"));
1612 Status
= EFI_OUT_OF_RESOURCES
;
1617 // Return the address to the user.
1619 *Entries
= FindData
;
1622 // Dump the entries.
1624 while (!NetMapIsEmpty (&FoundEntries
)) {
1626 // Get a cache entry from the map.
1628 CacheEntry
= NetMapRemoveHead (&FoundEntries
, (VOID
**)&CacheTable
);
1631 // Set the fields in FindData.
1633 FindData
->Size
= FoundEntryLength
;
1634 FindData
->DenyFlag
= (BOOLEAN
)(CacheTable
== &ArpService
->DeniedCacheTable
);
1635 FindData
->StaticFlag
= (BOOLEAN
)(CacheEntry
->DefaultDecayTime
== 0);
1636 FindData
->HwAddressType
= ArpService
->SnpMode
.IfType
;
1637 FindData
->SwAddressType
= Instance
->ConfigData
.SwAddressType
;
1638 FindData
->HwAddressLength
= (UINT8
)ArpService
->SnpMode
.HwAddressSize
;
1639 FindData
->SwAddressLength
= Instance
->ConfigData
.SwAddressLength
;
1642 // Copy the software address.
1646 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1647 FindData
->SwAddressLength
1651 // Copy the hardware address.
1654 (UINT8
*)(FindData
+ 1) + FindData
->SwAddressLength
,
1655 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1656 FindData
->HwAddressLength
1660 // Slip to the next FindData.
1662 FindData
= (EFI_ARP_FIND_DATA
*)((UINT8
*)FindData
+ FoundEntryLength
);
1667 NetMapClean (&FoundEntries
);