2 The implementation of the ARP protocol.
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at<BR>
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 // Global variable of EFI ARP Protocol Interface.
20 EFI_ARP_PROTOCOL mEfiArpProtocolTemplate
= {
32 Initialize the instance context data.
34 @param[in] ArpService Pointer to the arp service context data this
36 @param[out] Instance Pointer to the instance context data.
43 IN ARP_SERVICE_DATA
*ArpService
,
44 OUT ARP_INSTANCE_DATA
*Instance
47 NET_CHECK_SIGNATURE (ArpService
, ARP_SERVICE_DATA_SIGNATURE
);
49 Instance
->Signature
= ARP_INSTANCE_DATA_SIGNATURE
;
50 Instance
->ArpService
= ArpService
;
52 CopyMem (&Instance
->ArpProto
, &mEfiArpProtocolTemplate
, sizeof (Instance
->ArpProto
));
54 Instance
->Configured
= FALSE
;
55 Instance
->InDestroy
= FALSE
;
57 InitializeListHead (&Instance
->List
);
62 Process the Arp packets received from Mnp, the procedure conforms to RFC826.
64 @param[in] Context Pointer to the context data registerd to the
77 ARP_SERVICE_DATA
*ArpService
;
78 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*RxToken
;
79 EFI_MANAGED_NETWORK_RECEIVE_DATA
*RxData
;
81 ARP_ADDRESS ArpAddress
;
82 ARP_CACHE_ENTRY
*CacheEntry
;
84 ARP_INSTANCE_DATA
*Instance
;
85 EFI_ARP_CONFIG_DATA
*ConfigData
;
86 NET_ARP_ADDRESS SenderAddress
[2];
91 ArpService
= (ARP_SERVICE_DATA
*)Context
;
92 NET_CHECK_SIGNATURE (ArpService
, ARP_SERVICE_DATA_SIGNATURE
);
94 RxToken
= &ArpService
->RxToken
;
96 if (RxToken
->Status
== EFI_ABORTED
) {
98 // The Token is aborted, possibly by arp itself, just return and the receiving
99 // process is stopped.
104 if (EFI_ERROR (RxToken
->Status
)) {
106 // Restart the receiving if any other error Status occurs.
108 goto RESTART_RECEIVE
;
112 // Status is EFI_SUCCESS, process the received frame.
114 RxData
= RxToken
->Packet
.RxData
;
118 if (RxData
->DataLength
< sizeof (ARP_HEAD
)) {
120 // Restart the receiving if packet size is not correct.
122 goto RESTART_RECEIVE
;
126 // Convert the byte order of the multi-byte fields.
128 Head
= (ARP_HEAD
*) RxData
->PacketData
;
129 Head
->HwType
= NTOHS (Head
->HwType
);
130 Head
->ProtoType
= NTOHS (Head
->ProtoType
);
131 Head
->OpCode
= NTOHS (Head
->OpCode
);
133 if (RxData
->DataLength
< (sizeof (ARP_HEAD
) + 2 * Head
->HwAddrLen
+ 2 * Head
->ProtoAddrLen
)) {
134 goto RESTART_RECEIVE
;
137 if ((Head
->HwType
!= ArpService
->SnpMode
.IfType
) ||
138 (Head
->HwAddrLen
!= ArpService
->SnpMode
.HwAddressSize
) ||
139 (RxData
->ProtocolType
!= ARP_ETHER_PROTO_TYPE
)) {
141 // The hardware type or the hardware address length doesn't match.
142 // There is a sanity check for the protocol type too.
148 // Set the pointers to the addresses contained in the arp packet.
150 ArpAddress
.SenderHwAddr
= (UINT8
*)(Head
+ 1);
151 ArpAddress
.SenderProtoAddr
= ArpAddress
.SenderHwAddr
+ Head
->HwAddrLen
;
152 ArpAddress
.TargetHwAddr
= ArpAddress
.SenderProtoAddr
+ Head
->ProtoAddrLen
;
153 ArpAddress
.TargetProtoAddr
= ArpAddress
.TargetHwAddr
+ Head
->HwAddrLen
;
155 SenderAddress
[Hardware
].Type
= Head
->HwType
;
156 SenderAddress
[Hardware
].Length
= Head
->HwAddrLen
;
157 SenderAddress
[Hardware
].AddressPtr
= ArpAddress
.SenderHwAddr
;
159 SenderAddress
[Protocol
].Type
= Head
->ProtoType
;
160 SenderAddress
[Protocol
].Length
= Head
->ProtoAddrLen
;
161 SenderAddress
[Protocol
].AddressPtr
= ArpAddress
.SenderProtoAddr
;
164 // First, check the denied cache table.
166 CacheEntry
= ArpFindDeniedCacheEntry (
168 &SenderAddress
[Protocol
],
169 &SenderAddress
[Hardware
]
171 if (CacheEntry
!= NULL
) {
173 // This address (either hardware or protocol address, or both) is configured to
174 // be a deny entry, silently skip the normal process.
179 ProtoMatched
= FALSE
;
182 NET_LIST_FOR_EACH (Entry
, &ArpService
->ChildrenList
) {
184 // Iterate all the children.
186 Instance
= NET_LIST_USER_STRUCT (Entry
, ARP_INSTANCE_DATA
, List
);
187 NET_CHECK_SIGNATURE (Instance
, ARP_INSTANCE_DATA_SIGNATURE
);
188 ConfigData
= &Instance
->ConfigData
;
190 if ((Instance
->Configured
) &&
191 (Head
->ProtoType
== ConfigData
->SwAddressType
) &&
192 (Head
->ProtoAddrLen
== ConfigData
->SwAddressLength
)) {
194 // The protocol type is matched for the received arp packet.
197 if (0 == CompareMem (
198 (VOID
*)ArpAddress
.TargetProtoAddr
,
199 ConfigData
->StationAddress
,
200 ConfigData
->SwAddressLength
203 // The arp driver has the target address required by the received arp packet.
213 // Protocol type unmatchable, skip.
219 // Check whether the sender's address information is already in the cache.
222 CacheEntry
= ArpFindNextCacheEntryInTable (
223 &ArpService
->ResolvedCacheTable
,
226 &SenderAddress
[Protocol
],
229 if (CacheEntry
!= NULL
) {
231 // Update the entry with the new information.
233 ArpFillAddressInCacheEntry (CacheEntry
, &SenderAddress
[Hardware
], NULL
);
234 CacheEntry
->DecayTime
= CacheEntry
->DefaultDecayTime
;
240 // This arp packet isn't targeted to us, skip now.
247 // Add the triplet <protocol type, sender protocol address, sender hardware address>
248 // to the translation table.
250 CacheEntry
= ArpFindNextCacheEntryInTable (
251 &ArpService
->PendingRequestTable
,
254 &SenderAddress
[Protocol
],
257 if (CacheEntry
== NULL
) {
259 // Allocate a new CacheEntry.
261 CacheEntry
= ArpAllocCacheEntry (NULL
);
262 if (CacheEntry
== NULL
) {
267 if (!IsListEmpty (&CacheEntry
->List
)) {
268 RemoveEntryList (&CacheEntry
->List
);
272 // Fill the addresses into the CacheEntry.
274 ArpFillAddressInCacheEntry (
276 &SenderAddress
[Hardware
],
277 &SenderAddress
[Protocol
]
283 ArpAddressResolved (CacheEntry
, NULL
, NULL
);
286 // Add this entry into the ResolvedCacheTable
288 InsertHeadList (&ArpService
->ResolvedCacheTable
, &CacheEntry
->List
);
291 if (Head
->OpCode
== ARP_OPCODE_REQUEST
) {
293 // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
296 ArpSendFrame (Instance
, CacheEntry
, ARP_OPCODE_REPLY
);
302 // Signal Mnp to recycle the RxData.
304 gBS
->SignalEvent (RxData
->RecycleEvent
);
309 // Continue to receive packets from Mnp.
311 Status
= ArpService
->Mnp
->Receive (ArpService
->Mnp
, RxToken
);
314 if (EFI_ERROR (Status
)) {
315 DEBUG ((EFI_D_ERROR
, "ArpOnFrameRcvd: ArpService->Mnp->Receive "
316 "failed, %r\n.", Status
));
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 registerd 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 registerd 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 ((EFI_D_ERROR
, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken
->Status
));
374 // Free the allocated memory and close the event.
376 FreePool (TxData
->FragmentTable
[0].FragmentBuffer
);
378 gBS
->CloseEvent (TxToken
->Event
);
383 Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.
385 @param[in] Event The Event this notify function registered to.
386 @param[in] Context Pointer to the context data registerd to the
400 // Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK
402 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 registerd 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
;
535 Match the two NET_ARP_ADDRESSes.
537 @param[in] AddressOne Pointer to the first address to match.
538 @param[in] AddressTwo Pointer to the second address to match.
540 @return The two addresses match or not.
545 IN NET_ARP_ADDRESS
*AddressOne
,
546 IN NET_ARP_ADDRESS
*AddressTwo
549 ASSERT (AddressOne
!= NULL
&& AddressTwo
!= NULL
);
551 if ((AddressOne
->Type
!= AddressTwo
->Type
) ||
552 (AddressOne
->Length
!= AddressTwo
->Length
)) {
554 // Either Type or Length doesn't match.
559 if ((AddressOne
->AddressPtr
!= NULL
) &&
561 AddressOne
->AddressPtr
,
562 AddressTwo
->AddressPtr
,
566 // 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.
648 Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
649 in the DeniedCacheTable.
651 @param[in] ArpService Pointer to the arp service context data.
652 @param[in] ProtocolAddress Pointer to the protocol address.
653 @param[in] HardwareAddress Pointer to the hardware address.
655 @return Pointer to the matched cache entry, if NULL no match is found.
659 ArpFindDeniedCacheEntry (
660 IN ARP_SERVICE_DATA
*ArpService
,
661 IN NET_ARP_ADDRESS
*ProtocolAddress OPTIONAL
,
662 IN NET_ARP_ADDRESS
*HardwareAddress OPTIONAL
665 ARP_CACHE_ENTRY
*CacheEntry
;
667 ASSERT ((ProtocolAddress
!= NULL
) || (HardwareAddress
!= NULL
));
668 NET_CHECK_SIGNATURE (ArpService
, ARP_SERVICE_DATA_SIGNATURE
);
672 if ((ProtocolAddress
!= NULL
) && (ProtocolAddress
->AddressPtr
!= NULL
)) {
674 // Find the cache entry in the DeniedCacheTable by the protocol address.
676 CacheEntry
= ArpFindNextCacheEntryInTable (
677 &ArpService
->DeniedCacheTable
,
683 if (CacheEntry
!= NULL
) {
691 if ((HardwareAddress
!= NULL
) && (HardwareAddress
->AddressPtr
!= NULL
)) {
693 // Find the cache entry in the DeniedCacheTable by the hardware address.
695 CacheEntry
= ArpFindNextCacheEntryInTable (
696 &ArpService
->DeniedCacheTable
,
709 Allocate a cache entry and initialize it.
711 @param[in] Instance Pointer to the instance context data.
713 @return Pointer to the new created cache entry.
718 IN ARP_INSTANCE_DATA
*Instance
721 ARP_CACHE_ENTRY
*CacheEntry
;
722 NET_ARP_ADDRESS
*Address
;
726 // Allocate memory for the cache entry.
728 CacheEntry
= AllocatePool (sizeof (ARP_CACHE_ENTRY
));
729 if (CacheEntry
== NULL
) {
736 InitializeListHead (&CacheEntry
->List
);
737 InitializeListHead (&CacheEntry
->UserRequestList
);
739 for (Index
= 0; Index
< 2; Index
++) {
741 // Init the address pointers to point to the concrete buffer.
743 Address
= &CacheEntry
->Addresses
[Index
];
744 Address
->AddressPtr
= Address
->Buffer
.ProtoAddress
;
748 // Zero the hardware address first.
750 ZeroMem (CacheEntry
->Addresses
[Hardware
].AddressPtr
, ARP_MAX_HARDWARE_ADDRESS_LEN
);
752 if (Instance
!= NULL
) {
754 // Inherit the parameters from the instance configuration.
756 CacheEntry
->RetryCount
= Instance
->ConfigData
.RetryCount
;
757 CacheEntry
->NextRetryTime
= Instance
->ConfigData
.RetryTimeOut
;
758 CacheEntry
->DefaultDecayTime
= Instance
->ConfigData
.EntryTimeOut
;
759 CacheEntry
->DecayTime
= Instance
->ConfigData
.EntryTimeOut
;
762 // Use the default parameters if this cache entry isn't allocate in a
765 CacheEntry
->RetryCount
= ARP_DEFAULT_RETRY_COUNT
;
766 CacheEntry
->NextRetryTime
= ARP_DEFAULT_RETRY_INTERVAL
;
767 CacheEntry
->DefaultDecayTime
= ARP_DEFAULT_TIMEOUT_VALUE
;
768 CacheEntry
->DecayTime
= ARP_DEFAULT_TIMEOUT_VALUE
;
776 Turn the CacheEntry into the resolved status.
778 @param[in] CacheEntry Pointer to the resolved cache entry.
779 @param[in] Instance Pointer to the instance context data.
780 @param[in] UserEvent Pointer to the UserEvent to notify.
782 @return The count of notifications sent to the instance.
787 IN ARP_CACHE_ENTRY
*CacheEntry
,
788 IN ARP_INSTANCE_DATA
*Instance OPTIONAL
,
789 IN EFI_EVENT UserEvent OPTIONAL
793 LIST_ENTRY
*NextEntry
;
794 USER_REQUEST_CONTEXT
*Context
;
800 // Iterate all the linked user requests to notify them.
802 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &CacheEntry
->UserRequestList
) {
803 Context
= NET_LIST_USER_STRUCT (Entry
, USER_REQUEST_CONTEXT
, List
);
805 if (((Instance
== NULL
) || (Context
->Instance
== Instance
)) &&
806 ((UserEvent
== NULL
) || (Context
->UserRequestEvent
== UserEvent
))) {
808 // Copy the address to the user-provided buffer and notify the user.
811 Context
->UserHwAddrBuffer
,
812 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
813 CacheEntry
->Addresses
[Hardware
].Length
815 gBS
->SignalEvent (Context
->UserRequestEvent
);
818 // Remove this user request and free the context data.
820 RemoveEntryList (&Context
->List
);
828 // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.
837 Fill the addresses in the CacheEntry using the information passed in by
840 @param[in] CacheEntry Pointer to the cache entry.
841 @param[in] HwAddr Pointer to the software address.
842 @param[in] SwAddr Pointer to the hardware address.
848 ArpFillAddressInCacheEntry (
849 IN ARP_CACHE_ENTRY
*CacheEntry
,
850 IN NET_ARP_ADDRESS
*HwAddr OPTIONAL
,
851 IN NET_ARP_ADDRESS
*SwAddr OPTIONAL
854 NET_ARP_ADDRESS
*Address
[2];
855 NET_ARP_ADDRESS
*CacheAddress
;
858 Address
[Hardware
] = HwAddr
;
859 Address
[Protocol
] = SwAddr
;
861 for (Index
= 0; Index
< 2; Index
++) {
862 if (Address
[Index
] != NULL
) {
864 // Fill the address if the passed in pointer is not NULL.
866 CacheAddress
= &CacheEntry
->Addresses
[Index
];
868 CacheAddress
->Type
= Address
[Index
]->Type
;
869 CacheAddress
->Length
= Address
[Index
]->Length
;
871 if (Address
[Index
]->AddressPtr
!= NULL
) {
873 // Copy it if the AddressPtr points to some buffer.
876 CacheAddress
->AddressPtr
,
877 Address
[Index
]->AddressPtr
,
882 // Zero the corresponding address buffer in the CacheEntry.
884 ZeroMem (CacheAddress
->AddressPtr
, CacheAddress
->Length
);
892 Configure the instance using the ConfigData. ConfigData is already validated.
894 @param[in] Instance Pointer to the instance context data to be
896 @param[in] ConfigData Pointer to the configuration data used to
897 configure the instance.
899 @retval EFI_SUCCESS The instance is configured with the ConfigData.
900 @retval EFI_ACCESS_DENIED The instance is already configured and the
901 ConfigData tries to reset some unchangeable
903 @retval EFI_INVALID_PARAMETER The ConfigData provides a non-unicast IPv4 address
904 when the SwAddressType is IPv4.
905 @retval EFI_OUT_OF_RESOURCES The instance fails to configure due to memory
910 ArpConfigureInstance (
911 IN ARP_INSTANCE_DATA
*Instance
,
912 IN EFI_ARP_CONFIG_DATA
*ConfigData OPTIONAL
915 EFI_ARP_CONFIG_DATA
*OldConfigData
;
918 OldConfigData
= &Instance
->ConfigData
;
920 if (ConfigData
!= NULL
) {
922 if (Instance
->Configured
) {
924 // The instance is configured, check the unchangeable fields.
926 if ((OldConfigData
->SwAddressType
!= ConfigData
->SwAddressType
) ||
927 (OldConfigData
->SwAddressLength
!= ConfigData
->SwAddressLength
) ||
929 OldConfigData
->StationAddress
,
930 ConfigData
->StationAddress
,
931 OldConfigData
->SwAddressLength
934 // Deny the unallowed changes.
936 return EFI_ACCESS_DENIED
;
940 // The instance is not configured.
943 if (ConfigData
->SwAddressType
== IPV4_ETHER_PROTO_TYPE
) {
944 CopyMem (&Ip
, ConfigData
->StationAddress
, sizeof (IP4_ADDR
));
946 if (IP4_IS_UNSPECIFIED (Ip
) || IP4_IS_LOCAL_BROADCAST (Ip
)) {
948 // The station address should not be zero or broadcast address.
950 return EFI_INVALID_PARAMETER
;
955 // Save the configuration.
957 CopyMem (OldConfigData
, ConfigData
, sizeof (*OldConfigData
));
959 OldConfigData
->StationAddress
= AllocatePool (OldConfigData
->SwAddressLength
);
960 if (OldConfigData
->StationAddress
== NULL
) {
961 DEBUG ((EFI_D_ERROR
, "ArpConfigInstance: AllocatePool for the StationAddress "
963 return EFI_OUT_OF_RESOURCES
;
967 // Save the StationAddress.
970 OldConfigData
->StationAddress
,
971 ConfigData
->StationAddress
,
972 OldConfigData
->SwAddressLength
976 // Set the state to configured.
978 Instance
->Configured
= TRUE
;
982 // Use the implementation specific values if the following field is zero.
984 OldConfigData
->EntryTimeOut
= (ConfigData
->EntryTimeOut
== 0) ?
985 ARP_DEFAULT_TIMEOUT_VALUE
: ConfigData
->EntryTimeOut
;
987 OldConfigData
->RetryCount
= (ConfigData
->RetryCount
== 0) ?
988 ARP_DEFAULT_RETRY_COUNT
: ConfigData
->RetryCount
;
990 OldConfigData
->RetryTimeOut
= (ConfigData
->RetryTimeOut
== 0) ?
991 ARP_DEFAULT_RETRY_INTERVAL
: ConfigData
->RetryTimeOut
;
994 // Reset the configuration.
997 if (Instance
->Configured
) {
999 // Cancel the arp requests issued by this instance.
1001 Instance
->ArpProto
.Cancel (&Instance
->ArpProto
, NULL
, NULL
);
1004 // Free the buffer previously allocated to hold the station address.
1006 FreePool (OldConfigData
->StationAddress
);
1009 Instance
->Configured
= FALSE
;
1017 Send out an arp frame using the CachEntry and the ArpOpCode.
1019 @param[in] Instance Pointer to the instance context data.
1020 @param[in] CacheEntry Pointer to the configuration data used to
1021 configure the instance.
1022 @param[in] ArpOpCode The opcode used to send out this Arp frame, either
1030 IN ARP_INSTANCE_DATA
*Instance
,
1031 IN ARP_CACHE_ENTRY
*CacheEntry
,
1036 EFI_MANAGED_NETWORK_COMPLETION_TOKEN
*TxToken
;
1037 EFI_MANAGED_NETWORK_TRANSMIT_DATA
*TxData
;
1040 ARP_SERVICE_DATA
*ArpService
;
1041 EFI_SIMPLE_NETWORK_MODE
*SnpMode
;
1042 EFI_ARP_CONFIG_DATA
*ConfigData
;
1046 ASSERT ((Instance
!= NULL
) && (CacheEntry
!= NULL
));
1049 // Allocate memory for the TxToken.
1051 TxToken
= AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN
));
1052 if (TxToken
== NULL
) {
1053 DEBUG ((EFI_D_ERROR
, "ArpSendFrame: Allocate memory for TxToken failed.\n"));
1057 TxToken
->Event
= NULL
;
1062 // Create the event for this TxToken.
1064 Status
= gBS
->CreateEvent (
1071 if (EFI_ERROR (Status
)) {
1072 DEBUG ((EFI_D_ERROR
, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
1077 // Allocate memory for the TxData used in the TxToken.
1079 TxData
= AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA
));
1080 if (TxData
== NULL
) {
1081 DEBUG ((EFI_D_ERROR
, "ArpSendFrame: Allocate memory for TxData failed.\n"));
1085 ArpService
= Instance
->ArpService
;
1086 SnpMode
= &ArpService
->SnpMode
;
1087 ConfigData
= &Instance
->ConfigData
;
1090 // Calculate the buffer length for this arp frame.
1092 TotalLength
= SnpMode
->MediaHeaderSize
+ sizeof (ARP_HEAD
) +
1093 2 * (ConfigData
->SwAddressLength
+ SnpMode
->HwAddressSize
);
1096 // Allocate buffer for the arp frame.
1098 Packet
= AllocatePool (TotalLength
);
1099 if (Packet
== NULL
) {
1100 DEBUG ((EFI_D_ERROR
, "ArpSendFrame: Allocate memory for Packet failed.\n"));
1101 ASSERT (Packet
!= NULL
);
1107 // The destination MAC address.
1109 if (ArpOpCode
== ARP_OPCODE_REQUEST
) {
1110 CopyMem (TmpPtr
, &SnpMode
->BroadcastAddress
, SnpMode
->HwAddressSize
);
1114 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1115 SnpMode
->HwAddressSize
1118 TmpPtr
+= SnpMode
->HwAddressSize
;
1121 // The source MAC address.
1123 CopyMem (TmpPtr
, &SnpMode
->CurrentAddress
, SnpMode
->HwAddressSize
);
1124 TmpPtr
+= SnpMode
->HwAddressSize
;
1127 // The ethernet protocol type.
1129 *(UINT16
*)TmpPtr
= HTONS (ARP_ETHER_PROTO_TYPE
);
1135 ArpHead
= (ARP_HEAD
*) TmpPtr
;
1136 ArpHead
->HwType
= HTONS ((UINT16
)SnpMode
->IfType
);
1137 ArpHead
->ProtoType
= HTONS (ConfigData
->SwAddressType
);
1138 ArpHead
->HwAddrLen
= (UINT8
)SnpMode
->HwAddressSize
;
1139 ArpHead
->ProtoAddrLen
= ConfigData
->SwAddressLength
;
1140 ArpHead
->OpCode
= HTONS (ArpOpCode
);
1141 TmpPtr
+= sizeof (ARP_HEAD
);
1144 // The sender hardware address.
1146 CopyMem (TmpPtr
, &SnpMode
->CurrentAddress
, SnpMode
->HwAddressSize
);
1147 TmpPtr
+= SnpMode
->HwAddressSize
;
1150 // The sender protocol address.
1152 CopyMem (TmpPtr
, ConfigData
->StationAddress
, ConfigData
->SwAddressLength
);
1153 TmpPtr
+= ConfigData
->SwAddressLength
;
1156 // The target hardware address.
1160 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1161 SnpMode
->HwAddressSize
1163 TmpPtr
+= SnpMode
->HwAddressSize
;
1166 // The target protocol address.
1170 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1171 ConfigData
->SwAddressLength
1175 // Set all the fields of the TxData.
1177 TxData
->DestinationAddress
= NULL
;
1178 TxData
->SourceAddress
= NULL
;
1179 TxData
->ProtocolType
= 0;
1180 TxData
->DataLength
= TotalLength
- SnpMode
->MediaHeaderSize
;
1181 TxData
->HeaderLength
= (UINT16
) SnpMode
->MediaHeaderSize
;
1182 TxData
->FragmentCount
= 1;
1184 TxData
->FragmentTable
[0].FragmentBuffer
= Packet
;
1185 TxData
->FragmentTable
[0].FragmentLength
= TotalLength
;
1188 // Associate the TxData with the TxToken.
1190 TxToken
->Packet
.TxData
= TxData
;
1191 TxToken
->Status
= EFI_NOT_READY
;
1194 // Send out this arp packet by Mnp.
1196 Status
= ArpService
->Mnp
->Transmit (ArpService
->Mnp
, TxToken
);
1197 if (EFI_ERROR (Status
)) {
1198 DEBUG ((EFI_D_ERROR
, "Mnp->Transmit failed, %r.\n", Status
));
1206 if (Packet
!= NULL
) {
1210 if (TxData
!= NULL
) {
1214 if (TxToken
->Event
!= NULL
) {
1215 gBS
->CloseEvent (TxToken
->Event
);
1223 Delete the cache entries in the specified CacheTable, using the BySwAddress,
1224 SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,
1225 the cache is deleted event it's a static entry.
1227 @param[in] CacheTable Pointer to the cache table to do the deletion.
1228 @param[in] BySwAddress Delete the cache entry by software address or by
1230 @param[in] SwAddressType The software address used to do the deletion.
1231 @param[in] AddressBuffer Pointer to the buffer containing the address to
1232 match for the deletion.
1233 @param[in] Force This deletion is forced or not.
1235 @return The count of the deleted cache entries.
1239 ArpDeleteCacheEntryInTable (
1240 IN LIST_ENTRY
*CacheTable
,
1241 IN BOOLEAN BySwAddress
,
1242 IN UINT16 SwAddressType
,
1243 IN UINT8
*AddressBuffer OPTIONAL
,
1248 LIST_ENTRY
*NextEntry
;
1249 ARP_CACHE_ENTRY
*CacheEntry
;
1254 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, CacheTable
) {
1255 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
1257 if ((CacheEntry
->DefaultDecayTime
== 0) && !Force
) {
1259 // It's a static entry and we are not forced to delete it, skip.
1265 if (SwAddressType
== CacheEntry
->Addresses
[Protocol
].Type
) {
1267 // Protocol address type matched. Check the address.
1269 if ((AddressBuffer
== NULL
) ||
1272 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1273 CacheEntry
->Addresses
[Protocol
].Length
1282 if ((AddressBuffer
== NULL
) ||
1285 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1286 CacheEntry
->Addresses
[Hardware
].Length
1300 // Delete this entry.
1302 RemoveEntryList (&CacheEntry
->List
);
1303 ASSERT (IsListEmpty (&CacheEntry
->UserRequestList
));
1304 FreePool (CacheEntry
);
1314 Delete cache entries in all the cache tables.
1316 @param[in] Instance Pointer to the instance context data.
1317 @param[in] BySwAddress Delete the cache entry by software address or by
1319 @param[in] AddressBuffer Pointer to the buffer containing the address to
1320 match for the deletion.
1321 @param[in] Force This deletion is forced or not.
1323 @return The count of the deleted cache entries.
1327 ArpDeleteCacheEntry (
1328 IN ARP_INSTANCE_DATA
*Instance
,
1329 IN BOOLEAN BySwAddress
,
1330 IN UINT8
*AddressBuffer OPTIONAL
,
1334 ARP_SERVICE_DATA
*ArpService
;
1337 NET_CHECK_SIGNATURE (Instance
, ARP_INSTANCE_DATA_SIGNATURE
);
1339 ArpService
= Instance
->ArpService
;
1342 // Delete the cache entries in the DeniedCacheTable.
1344 Count
= ArpDeleteCacheEntryInTable (
1345 &ArpService
->DeniedCacheTable
,
1347 Instance
->ConfigData
.SwAddressType
,
1353 // Delete the cache entries inthe ResolvedCacheTable.
1355 Count
+= ArpDeleteCacheEntryInTable (
1356 &ArpService
->ResolvedCacheTable
,
1358 Instance
->ConfigData
.SwAddressType
,
1368 Cancel the arp request.
1370 @param[in] Instance Pointer to the instance context data.
1371 @param[in] TargetSwAddress Pointer to the buffer containing the target
1372 software address to match the arp request.
1373 @param[in] UserEvent The user event used to notify this request
1376 @return The count of the cancelled requests.
1381 IN ARP_INSTANCE_DATA
*Instance
,
1382 IN VOID
*TargetSwAddress OPTIONAL
,
1383 IN EFI_EVENT UserEvent OPTIONAL
1386 ARP_SERVICE_DATA
*ArpService
;
1388 LIST_ENTRY
*NextEntry
;
1389 ARP_CACHE_ENTRY
*CacheEntry
;
1392 NET_CHECK_SIGNATURE (Instance
, ARP_INSTANCE_DATA_SIGNATURE
);
1394 ArpService
= Instance
->ArpService
;
1397 NET_LIST_FOR_EACH_SAFE (Entry
, NextEntry
, &ArpService
->PendingRequestTable
) {
1398 CacheEntry
= NET_LIST_USER_STRUCT (Entry
, ARP_CACHE_ENTRY
, List
);
1400 if ((TargetSwAddress
== NULL
) ||
1403 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1404 CacheEntry
->Addresses
[Protocol
].Length
1407 // This request entry matches the TargetSwAddress or all requests are to be
1408 // cancelled as TargetSwAddress is NULL.
1410 Count
+= ArpAddressResolved (CacheEntry
, Instance
, UserEvent
);
1412 if (IsListEmpty (&CacheEntry
->UserRequestList
)) {
1414 // No user requests any more, remove this request cache entry.
1416 RemoveEntryList (&CacheEntry
->List
);
1417 FreePool (CacheEntry
);
1427 Find the cache entry in the cache table.
1429 @param[in] Instance Pointer to the instance context data.
1430 @param[in] BySwAddress Set to TRUE to look for matching software protocol
1431 addresses. Set to FALSE to look for matching
1432 hardware protocol addresses.
1433 @param[in] AddressBuffer Pointer to address buffer. Set to NULL to match
1435 @param[out] EntryLength The size of an entry in the entries buffer.
1436 @param[out] EntryCount The number of ARP cache entries that are found by
1437 the specified criteria.
1438 @param[out] Entries Pointer to the buffer that will receive the ARP
1440 @param[in] Refresh Set to TRUE to refresh the timeout value of the
1441 matching ARP cache entry.
1443 @retval EFI_SUCCESS The requested ARP cache entries are copied into
1445 @retval EFI_NOT_FOUND No matching entries found.
1446 @retval EFI_OUT_OF_RESOURCE There is a memory allocation failure.
1451 IN ARP_INSTANCE_DATA
*Instance
,
1452 IN BOOLEAN BySwAddress
,
1453 IN VOID
*AddressBuffer OPTIONAL
,
1454 OUT UINT32
*EntryLength OPTIONAL
,
1455 OUT UINT32
*EntryCount OPTIONAL
,
1456 OUT EFI_ARP_FIND_DATA
**Entries OPTIONAL
,
1461 ARP_SERVICE_DATA
*ArpService
;
1462 NET_ARP_ADDRESS MatchAddress
;
1463 FIND_OPTYPE FindOpType
;
1464 LIST_ENTRY
*StartEntry
;
1465 ARP_CACHE_ENTRY
*CacheEntry
;
1466 NET_MAP FoundEntries
;
1468 EFI_ARP_FIND_DATA
*FindData
;
1469 LIST_ENTRY
*CacheTable
;
1470 UINT32 FoundEntryLength
;
1472 ArpService
= Instance
->ArpService
;
1475 // Init the FounEntries used to hold the found cache entries.
1477 NetMapInit (&FoundEntries
);
1480 // Set the MatchAddress.
1483 MatchAddress
.Type
= Instance
->ConfigData
.SwAddressType
;
1484 MatchAddress
.Length
= Instance
->ConfigData
.SwAddressLength
;
1485 FindOpType
= ByProtoAddress
;
1487 MatchAddress
.Type
= ArpService
->SnpMode
.IfType
;
1488 MatchAddress
.Length
= (UINT8
)ArpService
->SnpMode
.HwAddressSize
;
1489 FindOpType
= ByHwAddress
;
1492 MatchAddress
.AddressPtr
= AddressBuffer
;
1495 // Search the DeniedCacheTable
1500 // Try to find the matched entries in the DeniedCacheTable.
1502 CacheEntry
= ArpFindNextCacheEntryInTable (
1503 &ArpService
->DeniedCacheTable
,
1509 if (CacheEntry
== NULL
) {
1511 // Once the CacheEntry is NULL, there are no more matches.
1517 // Insert the found entry into the map.
1522 (VOID
*)&ArpService
->DeniedCacheTable
1526 // Let the next search start from this cache entry.
1528 StartEntry
= &CacheEntry
->List
;
1532 // Refresh the DecayTime if needed.
1534 CacheEntry
->DecayTime
= CacheEntry
->DefaultDecayTime
;
1539 // Search the ResolvedCacheTable
1543 CacheEntry
= ArpFindNextCacheEntryInTable (
1544 &ArpService
->ResolvedCacheTable
,
1550 if (CacheEntry
== NULL
) {
1552 // Once the CacheEntry is NULL, there are no more matches.
1558 // Insert the found entry into the map.
1563 (VOID
*)&ArpService
->ResolvedCacheTable
1567 // Let the next search start from this cache entry.
1569 StartEntry
= &CacheEntry
->List
;
1573 // Refresh the DecayTime if needed.
1575 CacheEntry
->DecayTime
= CacheEntry
->DefaultDecayTime
;
1579 Status
= EFI_SUCCESS
;
1581 FoundCount
= (UINT32
) NetMapGetCount (&FoundEntries
);
1582 if (FoundCount
== 0) {
1583 Status
= EFI_NOT_FOUND
;
1588 // Found the entry length, make sure its 8 bytes alignment.
1590 FoundEntryLength
= (((sizeof (EFI_ARP_FIND_DATA
) + Instance
->ConfigData
.SwAddressLength
+
1591 ArpService
->SnpMode
.HwAddressSize
) + 3) & ~(0x3));
1593 if (EntryLength
!= NULL
) {
1594 *EntryLength
= FoundEntryLength
;
1597 if (EntryCount
!= NULL
) {
1599 // Return the found entry count.
1601 *EntryCount
= FoundCount
;
1604 if (Entries
== NULL
) {
1609 // Allocate buffer to copy the found entries.
1611 FindData
= AllocatePool (FoundCount
* FoundEntryLength
);
1612 if (FindData
== NULL
) {
1613 DEBUG ((EFI_D_ERROR
, "ArpFindCacheEntry: Failed to allocate memory.\n"));
1614 Status
= EFI_OUT_OF_RESOURCES
;
1619 // Return the address to the user.
1621 *Entries
= FindData
;
1624 // Dump the entries.
1626 while (!NetMapIsEmpty (&FoundEntries
)) {
1628 // Get a cache entry from the map.
1630 CacheEntry
= NetMapRemoveHead (&FoundEntries
, (VOID
**)&CacheTable
);
1633 // Set the fields in FindData.
1635 FindData
->Size
= FoundEntryLength
;
1636 FindData
->DenyFlag
= (BOOLEAN
)(CacheTable
== &ArpService
->DeniedCacheTable
);
1637 FindData
->StaticFlag
= (BOOLEAN
)(CacheEntry
->DefaultDecayTime
== 0);
1638 FindData
->HwAddressType
= ArpService
->SnpMode
.IfType
;
1639 FindData
->SwAddressType
= Instance
->ConfigData
.SwAddressType
;
1640 FindData
->HwAddressLength
= (UINT8
)ArpService
->SnpMode
.HwAddressSize
;
1641 FindData
->SwAddressLength
= Instance
->ConfigData
.SwAddressLength
;
1644 // Copy the software address.
1648 CacheEntry
->Addresses
[Protocol
].AddressPtr
,
1649 FindData
->SwAddressLength
1653 // Copy the hardware address.
1656 (UINT8
*)(FindData
+ 1) + FindData
->SwAddressLength
,
1657 CacheEntry
->Addresses
[Hardware
].AddressPtr
,
1658 FindData
->HwAddressLength
1662 // Slip to the next FindData.
1664 FindData
= (EFI_ARP_FIND_DATA
*)((UINT8
*)FindData
+ FoundEntryLength
);
1669 NetMapClean (&FoundEntries
);