]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/ArpDxe/ArpImpl.c
NetworkPkg/ArpDxe: Recycle invalid ARP packets (CVE-2019-14559)
[mirror_edk2.git] / NetworkPkg / ArpDxe / ArpImpl.c
1 /** @file
2 The implementation of the ARP protocol.
3
4 Copyright (c) 2006 - 2020, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "ArpImpl.h"
10
11 //
12 // Global variable of EFI ARP Protocol Interface.
13 //
14 EFI_ARP_PROTOCOL mEfiArpProtocolTemplate = {
15 ArpConfigure,
16 ArpAdd,
17 ArpFind,
18 ArpDelete,
19 ArpFlush,
20 ArpRequest,
21 ArpCancel
22 };
23
24
25 /**
26 Initialize the instance context data.
27
28 @param[in] ArpService Pointer to the arp service context data this
29 instance belongs to.
30 @param[out] Instance Pointer to the instance context data.
31
32 @return None.
33
34 **/
35 VOID
36 ArpInitInstance (
37 IN ARP_SERVICE_DATA *ArpService,
38 OUT ARP_INSTANCE_DATA *Instance
39 )
40 {
41 NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
42
43 Instance->Signature = ARP_INSTANCE_DATA_SIGNATURE;
44 Instance->ArpService = ArpService;
45
46 CopyMem (&Instance->ArpProto, &mEfiArpProtocolTemplate, sizeof (Instance->ArpProto));
47
48 Instance->Configured = FALSE;
49 Instance->InDestroy = FALSE;
50
51 InitializeListHead (&Instance->List);
52 }
53
54
55 /**
56 Process the Arp packets received from Mnp, the procedure conforms to RFC826.
57
58 @param[in] Context Pointer to the context data registered to the
59 Event.
60
61 @return None.
62
63 **/
64 VOID
65 EFIAPI
66 ArpOnFrameRcvdDpc (
67 IN VOID *Context
68 )
69 {
70 EFI_STATUS Status;
71 ARP_SERVICE_DATA *ArpService;
72 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *RxToken;
73 EFI_MANAGED_NETWORK_RECEIVE_DATA *RxData;
74 ARP_HEAD *Head;
75 ARP_ADDRESS ArpAddress;
76 ARP_CACHE_ENTRY *CacheEntry;
77 LIST_ENTRY *Entry;
78 ARP_INSTANCE_DATA *Instance;
79 EFI_ARP_CONFIG_DATA *ConfigData;
80 NET_ARP_ADDRESS SenderAddress[2];
81 BOOLEAN ProtoMatched;
82 BOOLEAN IsTarget;
83 BOOLEAN MergeFlag;
84
85 ArpService = (ARP_SERVICE_DATA *)Context;
86 NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
87
88 RxToken = &ArpService->RxToken;
89
90 if (RxToken->Status == EFI_ABORTED) {
91 //
92 // The Token is aborted, possibly by arp itself, just return and the receiving
93 // process is stopped.
94 //
95 return;
96 }
97
98 if (EFI_ERROR (RxToken->Status)) {
99 //
100 // Restart the receiving if any other error Status occurs.
101 //
102 goto RESTART_RECEIVE;
103 }
104
105 //
106 // Status is EFI_SUCCESS, process the received frame.
107 //
108 RxData = RxToken->Packet.RxData;
109 //
110 // Sanity check.
111 //
112 if (RxData->DataLength < sizeof (ARP_HEAD)) {
113 //
114 // Restart the receiving if packet size is not correct.
115 //
116 goto RECYCLE_RXDATA;
117 }
118
119 //
120 // Convert the byte order of the multi-byte fields.
121 //
122 Head = (ARP_HEAD *) RxData->PacketData;
123 Head->HwType = NTOHS (Head->HwType);
124 Head->ProtoType = NTOHS (Head->ProtoType);
125 Head->OpCode = NTOHS (Head->OpCode);
126
127 if (RxData->DataLength < (sizeof (ARP_HEAD) + 2 * Head->HwAddrLen + 2 * Head->ProtoAddrLen)) {
128 goto RECYCLE_RXDATA;
129 }
130
131 if ((Head->HwType != ArpService->SnpMode.IfType) ||
132 (Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||
133 (RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {
134 //
135 // The hardware type or the hardware address length doesn't match.
136 // There is a sanity check for the protocol type too.
137 //
138 goto RECYCLE_RXDATA;
139 }
140
141 //
142 // Set the pointers to the addresses contained in the arp packet.
143 //
144 ArpAddress.SenderHwAddr = (UINT8 *)(Head + 1);
145 ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;
146 ArpAddress.TargetHwAddr = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;
147 ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;
148
149 SenderAddress[Hardware].Type = Head->HwType;
150 SenderAddress[Hardware].Length = Head->HwAddrLen;
151 SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;
152
153 SenderAddress[Protocol].Type = Head->ProtoType;
154 SenderAddress[Protocol].Length = Head->ProtoAddrLen;
155 SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;
156
157 //
158 // First, check the denied cache table.
159 //
160 CacheEntry = ArpFindDeniedCacheEntry (
161 ArpService,
162 &SenderAddress[Protocol],
163 &SenderAddress[Hardware]
164 );
165 if (CacheEntry != NULL) {
166 //
167 // This address (either hardware or protocol address, or both) is configured to
168 // be a deny entry, silently skip the normal process.
169 //
170 goto RECYCLE_RXDATA;
171 }
172
173 ProtoMatched = FALSE;
174 IsTarget = FALSE;
175 Instance = NULL;
176 NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {
177 //
178 // Iterate all the children.
179 //
180 Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);
181 NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
182 ConfigData = &Instance->ConfigData;
183
184 if ((Instance->Configured) &&
185 (Head->ProtoType == ConfigData->SwAddressType) &&
186 (Head->ProtoAddrLen == ConfigData->SwAddressLength)) {
187 //
188 // The protocol type is matched for the received arp packet.
189 //
190 ProtoMatched = TRUE;
191 if (0 == CompareMem (
192 (VOID *)ArpAddress.TargetProtoAddr,
193 ConfigData->StationAddress,
194 ConfigData->SwAddressLength
195 )) {
196 //
197 // The arp driver has the target address required by the received arp packet.
198 //
199 IsTarget = TRUE;
200 break;
201 }
202 }
203 }
204
205 if (!ProtoMatched) {
206 //
207 // Protocol type unmatchable, skip.
208 //
209 goto RECYCLE_RXDATA;
210 }
211
212 //
213 // Check whether the sender's address information is already in the cache.
214 //
215 MergeFlag = FALSE;
216 CacheEntry = ArpFindNextCacheEntryInTable (
217 &ArpService->ResolvedCacheTable,
218 NULL,
219 ByProtoAddress,
220 &SenderAddress[Protocol],
221 NULL
222 );
223 if (CacheEntry != NULL) {
224 //
225 // Update the entry with the new information.
226 //
227 ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);
228 CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
229 MergeFlag = TRUE;
230 }
231
232 if (!IsTarget) {
233 //
234 // This arp packet isn't targeted to us, skip now.
235 //
236 goto RECYCLE_RXDATA;
237 }
238
239 if (!MergeFlag) {
240 //
241 // Add the triplet <protocol type, sender protocol address, sender hardware address>
242 // to the translation table.
243 //
244 CacheEntry = ArpFindNextCacheEntryInTable (
245 &ArpService->PendingRequestTable,
246 NULL,
247 ByProtoAddress,
248 &SenderAddress[Protocol],
249 NULL
250 );
251 if (CacheEntry == NULL) {
252 //
253 // Allocate a new CacheEntry.
254 //
255 CacheEntry = ArpAllocCacheEntry (NULL);
256 if (CacheEntry == NULL) {
257 goto RECYCLE_RXDATA;
258 }
259 }
260
261 if (!IsListEmpty (&CacheEntry->List)) {
262 RemoveEntryList (&CacheEntry->List);
263 }
264
265 //
266 // Fill the addresses into the CacheEntry.
267 //
268 ArpFillAddressInCacheEntry (
269 CacheEntry,
270 &SenderAddress[Hardware],
271 &SenderAddress[Protocol]
272 );
273
274 //
275 // Inform the user.
276 //
277 ArpAddressResolved (CacheEntry, NULL, NULL);
278
279 //
280 // Add this entry into the ResolvedCacheTable
281 //
282 InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);
283 }
284
285 if (Head->OpCode == ARP_OPCODE_REQUEST) {
286 //
287 // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
288 // is not NULL.
289 //
290 ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);
291 }
292
293 RECYCLE_RXDATA:
294
295 //
296 // Signal Mnp to recycle the RxData.
297 //
298 gBS->SignalEvent (RxData->RecycleEvent);
299
300 RESTART_RECEIVE:
301
302 //
303 // Continue to receive packets from Mnp.
304 //
305 Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);
306
307 DEBUG_CODE (
308 if (EFI_ERROR (Status)) {
309 DEBUG ((EFI_D_ERROR, "ArpOnFrameRcvd: ArpService->Mnp->Receive "
310 "failed, %r\n.", Status));
311 }
312 );
313 }
314
315 /**
316 Queue ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK.
317
318 @param[in] Event The Event this notify function registered to.
319 @param[in] Context Pointer to the context data registered to the
320 Event.
321
322 @return None.
323
324 **/
325 VOID
326 EFIAPI
327 ArpOnFrameRcvd (
328 IN EFI_EVENT Event,
329 IN VOID *Context
330 )
331 {
332 //
333 // Request ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK
334 //
335 QueueDpc (TPL_CALLBACK, ArpOnFrameRcvdDpc, Context);
336 }
337
338 /**
339 Process the already sent arp packets.
340
341 @param[in] Context Pointer to the context data registered to the
342 Event.
343
344 @return None.
345
346 **/
347 VOID
348 EFIAPI
349 ArpOnFrameSentDpc (
350 IN VOID *Context
351 )
352 {
353 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TxToken;
354 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
355
356 ASSERT (Context != NULL);
357
358 TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;
359 TxData = TxToken->Packet.TxData;
360
361 DEBUG_CODE (
362 if (EFI_ERROR (TxToken->Status)) {
363 DEBUG ((EFI_D_ERROR, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));
364 }
365 );
366
367 //
368 // Free the allocated memory and close the event.
369 //
370 FreePool (TxData->FragmentTable[0].FragmentBuffer);
371 FreePool (TxData);
372 gBS->CloseEvent (TxToken->Event);
373 FreePool (TxToken);
374 }
375
376 /**
377 Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.
378
379 @param[in] Event The Event this notify function registered to.
380 @param[in] Context Pointer to the context data registered to the
381 Event.
382
383 @return None.
384
385 **/
386 VOID
387 EFIAPI
388 ArpOnFrameSent (
389 IN EFI_EVENT Event,
390 IN VOID *Context
391 )
392 {
393 //
394 // Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK
395 //
396 QueueDpc (TPL_CALLBACK, ArpOnFrameSentDpc, Context);
397 }
398
399
400 /**
401 Process the arp cache olding and drive the retrying arp requests.
402
403 @param[in] Event The Event this notify function registered to.
404 @param[in] Context Pointer to the context data registered to the
405 Event.
406
407 @return None.
408
409 **/
410 VOID
411 EFIAPI
412 ArpTimerHandler (
413 IN EFI_EVENT Event,
414 IN VOID *Context
415 )
416 {
417 ARP_SERVICE_DATA *ArpService;
418 LIST_ENTRY *Entry;
419 LIST_ENTRY *NextEntry;
420 LIST_ENTRY *ContextEntry;
421 ARP_CACHE_ENTRY *CacheEntry;
422 USER_REQUEST_CONTEXT *RequestContext;
423
424 ASSERT (Context != NULL);
425 ArpService = (ARP_SERVICE_DATA *)Context;
426
427 //
428 // Iterate all the pending requests to see whether a retry is needed to send out
429 // or the request finally fails because the retry time reaches the limitation.
430 //
431 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
432 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
433
434 if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {
435 //
436 // Timeout, if we can retry more, send out the request again, otherwise abort
437 // this request.
438 //
439 if (CacheEntry->RetryCount == 0) {
440 //
441 // Abort this request.
442 //
443 ArpAddressResolved (CacheEntry, NULL, NULL);
444 ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
445
446 RemoveEntryList (&CacheEntry->List);
447 FreePool (CacheEntry);
448 } else {
449 //
450 // resend the ARP request.
451 //
452 ASSERT (!IsListEmpty(&CacheEntry->UserRequestList));
453
454 ContextEntry = CacheEntry->UserRequestList.ForwardLink;
455 RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);
456
457 ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);
458
459 CacheEntry->RetryCount--;
460 CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;
461 }
462 } else {
463 //
464 // Update the NextRetryTime.
465 //
466 CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;
467 }
468 }
469
470 //
471 // Check the timeouts for the DeniedCacheTable.
472 //
473 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {
474 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
475 ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
476
477 if (CacheEntry->DefaultDecayTime == 0) {
478 //
479 // It's a static entry, skip it.
480 //
481 continue;
482 }
483
484 if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
485 //
486 // Time out, remove it.
487 //
488 RemoveEntryList (&CacheEntry->List);
489 FreePool (CacheEntry);
490 } else {
491 //
492 // Update the DecayTime.
493 //
494 CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
495 }
496 }
497
498 //
499 // Check the timeouts for the ResolvedCacheTable.
500 //
501 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {
502 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
503 ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
504
505 if (CacheEntry->DefaultDecayTime == 0) {
506 //
507 // It's a static entry, skip it.
508 //
509 continue;
510 }
511
512 if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
513 //
514 // Time out, remove it.
515 //
516 RemoveEntryList (&CacheEntry->List);
517 FreePool (CacheEntry);
518 } else {
519 //
520 // Update the DecayTime.
521 //
522 CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
523 }
524 }
525 }
526
527
528 /**
529 Match the two NET_ARP_ADDRESSes.
530
531 @param[in] AddressOne Pointer to the first address to match.
532 @param[in] AddressTwo Pointer to the second address to match.
533
534 @return The two addresses match or not.
535
536 **/
537 BOOLEAN
538 ArpMatchAddress (
539 IN NET_ARP_ADDRESS *AddressOne,
540 IN NET_ARP_ADDRESS *AddressTwo
541 )
542 {
543 ASSERT (AddressOne != NULL && AddressTwo != NULL);
544
545 if ((AddressOne->Type != AddressTwo->Type) ||
546 (AddressOne->Length != AddressTwo->Length)) {
547 //
548 // Either Type or Length doesn't match.
549 //
550 return FALSE;
551 }
552
553 if ((AddressOne->AddressPtr != NULL) &&
554 (CompareMem (
555 AddressOne->AddressPtr,
556 AddressTwo->AddressPtr,
557 AddressOne->Length
558 ) != 0)) {
559 //
560 // The address is not the same.
561 //
562 return FALSE;
563 }
564
565 return TRUE;
566 }
567
568
569 /**
570 Find the CacheEntry which matches the requirements in the specified CacheTable.
571
572 @param[in] CacheTable Pointer to the arp cache table.
573 @param[in] StartEntry Pointer to the start entry this search begins with
574 in the cache table.
575 @param[in] FindOpType The search type.
576 @param[in] ProtocolAddress Pointer to the protocol address to match.
577 @param[in] HardwareAddress Pointer to the hardware address to match.
578
579 @return Pointer to the matched arp cache entry, if NULL, no match is found.
580
581 **/
582 ARP_CACHE_ENTRY *
583 ArpFindNextCacheEntryInTable (
584 IN LIST_ENTRY *CacheTable,
585 IN LIST_ENTRY *StartEntry,
586 IN FIND_OPTYPE FindOpType,
587 IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,
588 IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL
589 )
590 {
591 LIST_ENTRY *Entry;
592 ARP_CACHE_ENTRY *CacheEntry;
593
594 if (StartEntry == NULL) {
595 //
596 // Start from the beginning of the table if no StartEntry is specified.
597 //
598 StartEntry = CacheTable;
599 }
600
601 for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {
602 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
603
604 if ((FindOpType & MATCH_SW_ADDRESS) != 0) {
605 //
606 // Find by the software address.
607 //
608 if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {
609 //
610 // The ProtocolAddress doesn't match, continue to the next cache entry.
611 //
612 continue;
613 }
614 }
615
616 if ((FindOpType & MATCH_HW_ADDRESS) != 0) {
617 //
618 // Find by the hardware address.
619 //
620 if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {
621 //
622 // The HardwareAddress doesn't match, continue to the next cache entry.
623 //
624 continue;
625 }
626 }
627
628 //
629 // The CacheEntry meets the requirements now, return this entry.
630 //
631 return CacheEntry;
632 }
633
634 //
635 // No matching.
636 //
637 return NULL;
638 }
639
640
641 /**
642 Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
643 in the DeniedCacheTable.
644
645 @param[in] ArpService Pointer to the arp service context data.
646 @param[in] ProtocolAddress Pointer to the protocol address.
647 @param[in] HardwareAddress Pointer to the hardware address.
648
649 @return Pointer to the matched cache entry, if NULL no match is found.
650
651 **/
652 ARP_CACHE_ENTRY *
653 ArpFindDeniedCacheEntry (
654 IN ARP_SERVICE_DATA *ArpService,
655 IN NET_ARP_ADDRESS *ProtocolAddress OPTIONAL,
656 IN NET_ARP_ADDRESS *HardwareAddress OPTIONAL
657 )
658 {
659 ARP_CACHE_ENTRY *CacheEntry;
660
661 ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));
662 NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
663
664 CacheEntry = NULL;
665
666 if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {
667 //
668 // Find the cache entry in the DeniedCacheTable by the protocol address.
669 //
670 CacheEntry = ArpFindNextCacheEntryInTable (
671 &ArpService->DeniedCacheTable,
672 NULL,
673 ByProtoAddress,
674 ProtocolAddress,
675 NULL
676 );
677 if (CacheEntry != NULL) {
678 //
679 // There is a match.
680 //
681 return CacheEntry;
682 }
683 }
684
685 if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {
686 //
687 // Find the cache entry in the DeniedCacheTable by the hardware address.
688 //
689 CacheEntry = ArpFindNextCacheEntryInTable (
690 &ArpService->DeniedCacheTable,
691 NULL,
692 ByHwAddress,
693 NULL,
694 HardwareAddress
695 );
696 }
697
698 return CacheEntry;
699 }
700
701
702 /**
703 Allocate a cache entry and initialize it.
704
705 @param[in] Instance Pointer to the instance context data.
706
707 @return Pointer to the new created cache entry.
708
709 **/
710 ARP_CACHE_ENTRY *
711 ArpAllocCacheEntry (
712 IN ARP_INSTANCE_DATA *Instance
713 )
714 {
715 ARP_CACHE_ENTRY *CacheEntry;
716 NET_ARP_ADDRESS *Address;
717 UINT16 Index;
718
719 //
720 // Allocate memory for the cache entry.
721 //
722 CacheEntry = AllocatePool (sizeof (ARP_CACHE_ENTRY));
723 if (CacheEntry == NULL) {
724 return NULL;
725 }
726
727 //
728 // Init the lists.
729 //
730 InitializeListHead (&CacheEntry->List);
731 InitializeListHead (&CacheEntry->UserRequestList);
732
733 for (Index = 0; Index < 2; Index++) {
734 //
735 // Init the address pointers to point to the concrete buffer.
736 //
737 Address = &CacheEntry->Addresses[Index];
738 Address->AddressPtr = Address->Buffer.ProtoAddress;
739 }
740
741 //
742 // Zero the hardware address first.
743 //
744 ZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);
745
746 if (Instance != NULL) {
747 //
748 // Inherit the parameters from the instance configuration.
749 //
750 CacheEntry->RetryCount = Instance->ConfigData.RetryCount;
751 CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;
752 CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;
753 CacheEntry->DecayTime = Instance->ConfigData.EntryTimeOut;
754 } else {
755 //
756 // Use the default parameters if this cache entry isn't allocate in a
757 // instance's scope.
758 //
759 CacheEntry->RetryCount = ARP_DEFAULT_RETRY_COUNT;
760 CacheEntry->NextRetryTime = ARP_DEFAULT_RETRY_INTERVAL;
761 CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
762 CacheEntry->DecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
763 }
764
765 return CacheEntry;
766 }
767
768
769 /**
770 Turn the CacheEntry into the resolved status.
771
772 @param[in] CacheEntry Pointer to the resolved cache entry.
773 @param[in] Instance Pointer to the instance context data.
774 @param[in] UserEvent Pointer to the UserEvent to notify.
775
776 @return The count of notifications sent to the instance.
777
778 **/
779 UINTN
780 ArpAddressResolved (
781 IN ARP_CACHE_ENTRY *CacheEntry,
782 IN ARP_INSTANCE_DATA *Instance OPTIONAL,
783 IN EFI_EVENT UserEvent OPTIONAL
784 )
785 {
786 LIST_ENTRY *Entry;
787 LIST_ENTRY *NextEntry;
788 USER_REQUEST_CONTEXT *Context;
789 UINTN Count;
790
791 Count = 0;
792
793 //
794 // Iterate all the linked user requests to notify them.
795 //
796 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {
797 Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);
798
799 if (((Instance == NULL) || (Context->Instance == Instance)) &&
800 ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {
801 //
802 // Copy the address to the user-provided buffer and notify the user.
803 //
804 CopyMem (
805 Context->UserHwAddrBuffer,
806 CacheEntry->Addresses[Hardware].AddressPtr,
807 CacheEntry->Addresses[Hardware].Length
808 );
809 gBS->SignalEvent (Context->UserRequestEvent);
810
811 //
812 // Remove this user request and free the context data.
813 //
814 RemoveEntryList (&Context->List);
815 FreePool (Context);
816
817 Count++;
818 }
819 }
820
821 //
822 // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.
823 //
824 DispatchDpc ();
825
826 return Count;
827 }
828
829
830 /**
831 Fill the addresses in the CacheEntry using the information passed in by
832 HwAddr and SwAddr.
833
834 @param[in] CacheEntry Pointer to the cache entry.
835 @param[in] HwAddr Pointer to the software address.
836 @param[in] SwAddr Pointer to the hardware address.
837
838 @return None.
839
840 **/
841 VOID
842 ArpFillAddressInCacheEntry (
843 IN ARP_CACHE_ENTRY *CacheEntry,
844 IN NET_ARP_ADDRESS *HwAddr OPTIONAL,
845 IN NET_ARP_ADDRESS *SwAddr OPTIONAL
846 )
847 {
848 NET_ARP_ADDRESS *Address[2];
849 NET_ARP_ADDRESS *CacheAddress;
850 UINT32 Index;
851
852 Address[Hardware] = HwAddr;
853 Address[Protocol] = SwAddr;
854
855 for (Index = 0; Index < 2; Index++) {
856 if (Address[Index] != NULL) {
857 //
858 // Fill the address if the passed in pointer is not NULL.
859 //
860 CacheAddress = &CacheEntry->Addresses[Index];
861
862 CacheAddress->Type = Address[Index]->Type;
863 CacheAddress->Length = Address[Index]->Length;
864
865 if (Address[Index]->AddressPtr != NULL) {
866 //
867 // Copy it if the AddressPtr points to some buffer.
868 //
869 CopyMem (
870 CacheAddress->AddressPtr,
871 Address[Index]->AddressPtr,
872 CacheAddress->Length
873 );
874 } else {
875 //
876 // Zero the corresponding address buffer in the CacheEntry.
877 //
878 ZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);
879 }
880 }
881 }
882 }
883
884
885 /**
886 Configure the instance using the ConfigData. ConfigData is already validated.
887
888 @param[in] Instance Pointer to the instance context data to be
889 configured.
890 @param[in] ConfigData Pointer to the configuration data used to
891 configure the instance.
892
893 @retval EFI_SUCCESS The instance is configured with the ConfigData.
894 @retval EFI_ACCESS_DENIED The instance is already configured and the
895 ConfigData tries to reset some unchangeable
896 fields.
897 @retval EFI_INVALID_PARAMETER The ConfigData provides a non-unicast IPv4 address
898 when the SwAddressType is IPv4.
899 @retval EFI_OUT_OF_RESOURCES The instance fails to configure due to memory
900 limitation.
901
902 **/
903 EFI_STATUS
904 ArpConfigureInstance (
905 IN ARP_INSTANCE_DATA *Instance,
906 IN EFI_ARP_CONFIG_DATA *ConfigData OPTIONAL
907 )
908 {
909 EFI_ARP_CONFIG_DATA *OldConfigData;
910 IP4_ADDR Ip;
911
912 OldConfigData = &Instance->ConfigData;
913
914 if (ConfigData != NULL) {
915
916 if (Instance->Configured) {
917 //
918 // The instance is configured, check the unchangeable fields.
919 //
920 if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||
921 (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||
922 (CompareMem (
923 OldConfigData->StationAddress,
924 ConfigData->StationAddress,
925 OldConfigData->SwAddressLength
926 ) != 0)) {
927 //
928 // Deny the unallowed changes.
929 //
930 return EFI_ACCESS_DENIED;
931 }
932 } else {
933 //
934 // The instance is not configured.
935 //
936
937 if (ConfigData->SwAddressType == IPV4_ETHER_PROTO_TYPE) {
938 CopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));
939
940 if (IP4_IS_UNSPECIFIED (Ip) || IP4_IS_LOCAL_BROADCAST (Ip)) {
941 //
942 // The station address should not be zero or broadcast address.
943 //
944 return EFI_INVALID_PARAMETER;
945 }
946 }
947
948 //
949 // Save the configuration.
950 //
951 CopyMem (OldConfigData, ConfigData, sizeof (*OldConfigData));
952
953 OldConfigData->StationAddress = AllocatePool (OldConfigData->SwAddressLength);
954 if (OldConfigData->StationAddress == NULL) {
955 DEBUG ((EFI_D_ERROR, "ArpConfigInstance: AllocatePool for the StationAddress "
956 "failed.\n"));
957 return EFI_OUT_OF_RESOURCES;
958 }
959
960 //
961 // Save the StationAddress.
962 //
963 CopyMem (
964 OldConfigData->StationAddress,
965 ConfigData->StationAddress,
966 OldConfigData->SwAddressLength
967 );
968
969 //
970 // Set the state to configured.
971 //
972 Instance->Configured = TRUE;
973 }
974
975 //
976 // Use the implementation specific values if the following field is zero.
977 //
978 OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?
979 ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;
980
981 OldConfigData->RetryCount = (ConfigData->RetryCount == 0) ?
982 ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;
983
984 OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?
985 ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;
986 } else {
987 //
988 // Reset the configuration.
989 //
990
991 if (Instance->Configured) {
992 //
993 // Cancel the arp requests issued by this instance.
994 //
995 Instance->ArpProto.Cancel (&Instance->ArpProto, NULL, NULL);
996
997 //
998 // Free the buffer previously allocated to hold the station address.
999 //
1000 FreePool (OldConfigData->StationAddress);
1001 }
1002
1003 Instance->Configured = FALSE;
1004 }
1005
1006 return EFI_SUCCESS;
1007 }
1008
1009
1010 /**
1011 Send out an arp frame using the CacheEntry and the ArpOpCode.
1012
1013 @param[in] Instance Pointer to the instance context data.
1014 @param[in] CacheEntry Pointer to the configuration data used to
1015 configure the instance.
1016 @param[in] ArpOpCode The opcode used to send out this Arp frame, either
1017 request or reply.
1018
1019 @return None.
1020
1021 **/
1022 VOID
1023 ArpSendFrame (
1024 IN ARP_INSTANCE_DATA *Instance,
1025 IN ARP_CACHE_ENTRY *CacheEntry,
1026 IN UINT16 ArpOpCode
1027 )
1028 {
1029 EFI_STATUS Status;
1030 EFI_MANAGED_NETWORK_COMPLETION_TOKEN *TxToken;
1031 EFI_MANAGED_NETWORK_TRANSMIT_DATA *TxData;
1032 UINT32 TotalLength;
1033 UINT8 *Packet;
1034 ARP_SERVICE_DATA *ArpService;
1035 EFI_SIMPLE_NETWORK_MODE *SnpMode;
1036 EFI_ARP_CONFIG_DATA *ConfigData;
1037 UINT8 *TmpPtr;
1038 ARP_HEAD *ArpHead;
1039
1040 ASSERT ((Instance != NULL) && (CacheEntry != NULL));
1041
1042 //
1043 // Allocate memory for the TxToken.
1044 //
1045 TxToken = AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));
1046 if (TxToken == NULL) {
1047 DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxToken failed.\n"));
1048 return;
1049 }
1050
1051 TxToken->Event = NULL;
1052 TxData = NULL;
1053 Packet = NULL;
1054
1055 //
1056 // Create the event for this TxToken.
1057 //
1058 Status = gBS->CreateEvent (
1059 EVT_NOTIFY_SIGNAL,
1060 TPL_NOTIFY,
1061 ArpOnFrameSent,
1062 (VOID *)TxToken,
1063 &TxToken->Event
1064 );
1065 if (EFI_ERROR (Status)) {
1066 DEBUG ((EFI_D_ERROR, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
1067 goto CLEAN_EXIT;
1068 }
1069
1070 //
1071 // Allocate memory for the TxData used in the TxToken.
1072 //
1073 TxData = AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));
1074 if (TxData == NULL) {
1075 DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxData failed.\n"));
1076 goto CLEAN_EXIT;
1077 }
1078
1079 ArpService = Instance->ArpService;
1080 SnpMode = &ArpService->SnpMode;
1081 ConfigData = &Instance->ConfigData;
1082
1083 //
1084 // Calculate the buffer length for this arp frame.
1085 //
1086 TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +
1087 2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);
1088
1089 //
1090 // Allocate buffer for the arp frame.
1091 //
1092 Packet = AllocatePool (TotalLength);
1093 if (Packet == NULL) {
1094 DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for Packet failed.\n"));
1095 ASSERT (Packet != NULL);
1096 }
1097
1098 TmpPtr = Packet;
1099
1100 //
1101 // The destination MAC address.
1102 //
1103 if (ArpOpCode == ARP_OPCODE_REQUEST) {
1104 CopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
1105 } else {
1106 CopyMem (
1107 TmpPtr,
1108 CacheEntry->Addresses[Hardware].AddressPtr,
1109 SnpMode->HwAddressSize
1110 );
1111 }
1112 TmpPtr += SnpMode->HwAddressSize;
1113
1114 //
1115 // The source MAC address.
1116 //
1117 CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
1118 TmpPtr += SnpMode->HwAddressSize;
1119
1120 //
1121 // The ethernet protocol type.
1122 //
1123 *(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);
1124 TmpPtr += 2;
1125
1126 //
1127 // The ARP Head.
1128 //
1129 ArpHead = (ARP_HEAD *) TmpPtr;
1130 ArpHead->HwType = HTONS ((UINT16)SnpMode->IfType);
1131 ArpHead->ProtoType = HTONS (ConfigData->SwAddressType);
1132 ArpHead->HwAddrLen = (UINT8)SnpMode->HwAddressSize;
1133 ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;
1134 ArpHead->OpCode = HTONS (ArpOpCode);
1135 TmpPtr += sizeof (ARP_HEAD);
1136
1137 //
1138 // The sender hardware address.
1139 //
1140 CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
1141 TmpPtr += SnpMode->HwAddressSize;
1142
1143 //
1144 // The sender protocol address.
1145 //
1146 CopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);
1147 TmpPtr += ConfigData->SwAddressLength;
1148
1149 //
1150 // The target hardware address.
1151 //
1152 CopyMem (
1153 TmpPtr,
1154 CacheEntry->Addresses[Hardware].AddressPtr,
1155 SnpMode->HwAddressSize
1156 );
1157 TmpPtr += SnpMode->HwAddressSize;
1158
1159 //
1160 // The target protocol address.
1161 //
1162 CopyMem (
1163 TmpPtr,
1164 CacheEntry->Addresses[Protocol].AddressPtr,
1165 ConfigData->SwAddressLength
1166 );
1167
1168 //
1169 // Set all the fields of the TxData.
1170 //
1171 TxData->DestinationAddress = NULL;
1172 TxData->SourceAddress = NULL;
1173 TxData->ProtocolType = 0;
1174 TxData->DataLength = TotalLength - SnpMode->MediaHeaderSize;
1175 TxData->HeaderLength = (UINT16) SnpMode->MediaHeaderSize;
1176 TxData->FragmentCount = 1;
1177
1178 TxData->FragmentTable[0].FragmentBuffer = Packet;
1179 TxData->FragmentTable[0].FragmentLength = TotalLength;
1180
1181 //
1182 // Associate the TxData with the TxToken.
1183 //
1184 TxToken->Packet.TxData = TxData;
1185 TxToken->Status = EFI_NOT_READY;
1186
1187 //
1188 // Send out this arp packet by Mnp.
1189 //
1190 Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);
1191 if (EFI_ERROR (Status)) {
1192 DEBUG ((EFI_D_ERROR, "Mnp->Transmit failed, %r.\n", Status));
1193 goto CLEAN_EXIT;
1194 }
1195
1196 return;
1197
1198 CLEAN_EXIT:
1199
1200 if (Packet != NULL) {
1201 FreePool (Packet);
1202 }
1203
1204 if (TxData != NULL) {
1205 FreePool (TxData);
1206 }
1207
1208 if (TxToken->Event != NULL) {
1209 gBS->CloseEvent (TxToken->Event);
1210 }
1211
1212 FreePool (TxToken);
1213 }
1214
1215
1216 /**
1217 Delete the cache entries in the specified CacheTable, using the BySwAddress,
1218 SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,
1219 the cache is deleted event it's a static entry.
1220
1221 @param[in] CacheTable Pointer to the cache table to do the deletion.
1222 @param[in] BySwAddress Delete the cache entry by software address or by
1223 hardware address.
1224 @param[in] SwAddressType The software address used to do the deletion.
1225 @param[in] AddressBuffer Pointer to the buffer containing the address to
1226 match for the deletion.
1227 @param[in] Force This deletion is forced or not.
1228
1229 @return The count of the deleted cache entries.
1230
1231 **/
1232 UINTN
1233 ArpDeleteCacheEntryInTable (
1234 IN LIST_ENTRY *CacheTable,
1235 IN BOOLEAN BySwAddress,
1236 IN UINT16 SwAddressType,
1237 IN UINT8 *AddressBuffer OPTIONAL,
1238 IN BOOLEAN Force
1239 )
1240 {
1241 LIST_ENTRY *Entry;
1242 LIST_ENTRY *NextEntry;
1243 ARP_CACHE_ENTRY *CacheEntry;
1244 UINTN Count;
1245
1246 Count = 0;
1247
1248 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {
1249 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
1250
1251 if ((CacheEntry->DefaultDecayTime == 0) && !Force) {
1252 //
1253 // It's a static entry and we are not forced to delete it, skip.
1254 //
1255 continue;
1256 }
1257
1258 if (BySwAddress) {
1259 if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {
1260 //
1261 // Protocol address type matched. Check the address.
1262 //
1263 if ((AddressBuffer == NULL) ||
1264 (CompareMem (
1265 AddressBuffer,
1266 CacheEntry->Addresses[Protocol].AddressPtr,
1267 CacheEntry->Addresses[Protocol].Length
1268 ) == 0)) {
1269 //
1270 // Address matched.
1271 //
1272 goto MATCHED;
1273 }
1274 }
1275 } else {
1276 if ((AddressBuffer == NULL) ||
1277 (CompareMem (
1278 AddressBuffer,
1279 CacheEntry->Addresses[Hardware].AddressPtr,
1280 CacheEntry->Addresses[Hardware].Length
1281 ) == 0)) {
1282 //
1283 // Address matched.
1284 //
1285 goto MATCHED;
1286 }
1287 }
1288
1289 continue;
1290
1291 MATCHED:
1292
1293 //
1294 // Delete this entry.
1295 //
1296 RemoveEntryList (&CacheEntry->List);
1297 ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
1298 FreePool (CacheEntry);
1299
1300 Count++;
1301 }
1302
1303 return Count;
1304 }
1305
1306
1307 /**
1308 Delete cache entries in all the cache tables.
1309
1310 @param[in] Instance Pointer to the instance context data.
1311 @param[in] BySwAddress Delete the cache entry by software address or by
1312 hardware address.
1313 @param[in] AddressBuffer Pointer to the buffer containing the address to
1314 match for the deletion.
1315 @param[in] Force This deletion is forced or not.
1316
1317 @return The count of the deleted cache entries.
1318
1319 **/
1320 UINTN
1321 ArpDeleteCacheEntry (
1322 IN ARP_INSTANCE_DATA *Instance,
1323 IN BOOLEAN BySwAddress,
1324 IN UINT8 *AddressBuffer OPTIONAL,
1325 IN BOOLEAN Force
1326 )
1327 {
1328 ARP_SERVICE_DATA *ArpService;
1329 UINTN Count;
1330
1331 NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
1332
1333 ArpService = Instance->ArpService;
1334
1335 //
1336 // Delete the cache entries in the DeniedCacheTable.
1337 //
1338 Count = ArpDeleteCacheEntryInTable (
1339 &ArpService->DeniedCacheTable,
1340 BySwAddress,
1341 Instance->ConfigData.SwAddressType,
1342 AddressBuffer,
1343 Force
1344 );
1345
1346 //
1347 // Delete the cache entries in the ResolvedCacheTable.
1348 //
1349 Count += ArpDeleteCacheEntryInTable (
1350 &ArpService->ResolvedCacheTable,
1351 BySwAddress,
1352 Instance->ConfigData.SwAddressType,
1353 AddressBuffer,
1354 Force
1355 );
1356
1357 return Count;
1358 }
1359
1360
1361 /**
1362 Cancel the arp request.
1363
1364 @param[in] Instance Pointer to the instance context data.
1365 @param[in] TargetSwAddress Pointer to the buffer containing the target
1366 software address to match the arp request.
1367 @param[in] UserEvent The user event used to notify this request
1368 cancellation.
1369
1370 @return The count of the cancelled requests.
1371
1372 **/
1373 UINTN
1374 ArpCancelRequest (
1375 IN ARP_INSTANCE_DATA *Instance,
1376 IN VOID *TargetSwAddress OPTIONAL,
1377 IN EFI_EVENT UserEvent OPTIONAL
1378 )
1379 {
1380 ARP_SERVICE_DATA *ArpService;
1381 LIST_ENTRY *Entry;
1382 LIST_ENTRY *NextEntry;
1383 ARP_CACHE_ENTRY *CacheEntry;
1384 UINTN Count;
1385
1386 NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
1387
1388 ArpService = Instance->ArpService;
1389
1390 Count = 0;
1391 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
1392 CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
1393
1394 if ((TargetSwAddress == NULL) ||
1395 (CompareMem (
1396 TargetSwAddress,
1397 CacheEntry->Addresses[Protocol].AddressPtr,
1398 CacheEntry->Addresses[Protocol].Length
1399 ) == 0)) {
1400 //
1401 // This request entry matches the TargetSwAddress or all requests are to be
1402 // cancelled as TargetSwAddress is NULL.
1403 //
1404 Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);
1405
1406 if (IsListEmpty (&CacheEntry->UserRequestList)) {
1407 //
1408 // No user requests any more, remove this request cache entry.
1409 //
1410 RemoveEntryList (&CacheEntry->List);
1411 FreePool (CacheEntry);
1412 }
1413 }
1414 }
1415
1416 return Count;
1417 }
1418
1419
1420 /**
1421 Find the cache entry in the cache table.
1422
1423 @param[in] Instance Pointer to the instance context data.
1424 @param[in] BySwAddress Set to TRUE to look for matching software protocol
1425 addresses. Set to FALSE to look for matching
1426 hardware protocol addresses.
1427 @param[in] AddressBuffer Pointer to address buffer. Set to NULL to match
1428 all addresses.
1429 @param[out] EntryLength The size of an entry in the entries buffer.
1430 @param[out] EntryCount The number of ARP cache entries that are found by
1431 the specified criteria.
1432 @param[out] Entries Pointer to the buffer that will receive the ARP
1433 cache entries.
1434 @param[in] Refresh Set to TRUE to refresh the timeout value of the
1435 matching ARP cache entry.
1436
1437 @retval EFI_SUCCESS The requested ARP cache entries are copied into
1438 the buffer.
1439 @retval EFI_NOT_FOUND No matching entries found.
1440 @retval EFI_OUT_OF_RESOURCE There is a memory allocation failure.
1441
1442 **/
1443 EFI_STATUS
1444 ArpFindCacheEntry (
1445 IN ARP_INSTANCE_DATA *Instance,
1446 IN BOOLEAN BySwAddress,
1447 IN VOID *AddressBuffer OPTIONAL,
1448 OUT UINT32 *EntryLength OPTIONAL,
1449 OUT UINT32 *EntryCount OPTIONAL,
1450 OUT EFI_ARP_FIND_DATA **Entries OPTIONAL,
1451 IN BOOLEAN Refresh
1452 )
1453 {
1454 EFI_STATUS Status;
1455 ARP_SERVICE_DATA *ArpService;
1456 NET_ARP_ADDRESS MatchAddress;
1457 FIND_OPTYPE FindOpType;
1458 LIST_ENTRY *StartEntry;
1459 ARP_CACHE_ENTRY *CacheEntry;
1460 NET_MAP FoundEntries;
1461 UINT32 FoundCount;
1462 EFI_ARP_FIND_DATA *FindData;
1463 LIST_ENTRY *CacheTable;
1464 UINT32 FoundEntryLength;
1465
1466 ArpService = Instance->ArpService;
1467
1468 //
1469 // Init the FoundEntries used to hold the found cache entries.
1470 //
1471 NetMapInit (&FoundEntries);
1472
1473 //
1474 // Set the MatchAddress.
1475 //
1476 if (BySwAddress) {
1477 MatchAddress.Type = Instance->ConfigData.SwAddressType;
1478 MatchAddress.Length = Instance->ConfigData.SwAddressLength;
1479 FindOpType = ByProtoAddress;
1480 } else {
1481 MatchAddress.Type = ArpService->SnpMode.IfType;
1482 MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;
1483 FindOpType = ByHwAddress;
1484 }
1485
1486 MatchAddress.AddressPtr = AddressBuffer;
1487
1488 //
1489 // Search the DeniedCacheTable
1490 //
1491 StartEntry = NULL;
1492 while (TRUE) {
1493 //
1494 // Try to find the matched entries in the DeniedCacheTable.
1495 //
1496 CacheEntry = ArpFindNextCacheEntryInTable (
1497 &ArpService->DeniedCacheTable,
1498 StartEntry,
1499 FindOpType,
1500 &MatchAddress,
1501 &MatchAddress
1502 );
1503 if (CacheEntry == NULL) {
1504 //
1505 // Once the CacheEntry is NULL, there are no more matches.
1506 //
1507 break;
1508 }
1509
1510 //
1511 // Insert the found entry into the map.
1512 //
1513 NetMapInsertTail (
1514 &FoundEntries,
1515 (VOID *)CacheEntry,
1516 (VOID *)&ArpService->DeniedCacheTable
1517 );
1518
1519 //
1520 // Let the next search start from this cache entry.
1521 //
1522 StartEntry = &CacheEntry->List;
1523
1524 if (Refresh) {
1525 //
1526 // Refresh the DecayTime if needed.
1527 //
1528 CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
1529 }
1530 }
1531
1532 //
1533 // Search the ResolvedCacheTable
1534 //
1535 StartEntry = NULL;
1536 while (TRUE) {
1537 CacheEntry = ArpFindNextCacheEntryInTable (
1538 &ArpService->ResolvedCacheTable,
1539 StartEntry,
1540 FindOpType,
1541 &MatchAddress,
1542 &MatchAddress
1543 );
1544 if (CacheEntry == NULL) {
1545 //
1546 // Once the CacheEntry is NULL, there are no more matches.
1547 //
1548 break;
1549 }
1550
1551 //
1552 // Insert the found entry into the map.
1553 //
1554 NetMapInsertTail (
1555 &FoundEntries,
1556 (VOID *)CacheEntry,
1557 (VOID *)&ArpService->ResolvedCacheTable
1558 );
1559
1560 //
1561 // Let the next search start from this cache entry.
1562 //
1563 StartEntry = &CacheEntry->List;
1564
1565 if (Refresh) {
1566 //
1567 // Refresh the DecayTime if needed.
1568 //
1569 CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
1570 }
1571 }
1572
1573 Status = EFI_SUCCESS;
1574
1575 FoundCount = (UINT32) NetMapGetCount (&FoundEntries);
1576 if (FoundCount == 0) {
1577 Status = EFI_NOT_FOUND;
1578 goto CLEAN_EXIT;
1579 }
1580
1581 //
1582 // Found the entry length, make sure its 8 bytes alignment.
1583 //
1584 FoundEntryLength = (((sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +
1585 ArpService->SnpMode.HwAddressSize) + 3) & ~(0x3));
1586
1587 if (EntryLength != NULL) {
1588 *EntryLength = FoundEntryLength;
1589 }
1590
1591 if (EntryCount != NULL) {
1592 //
1593 // Return the found entry count.
1594 //
1595 *EntryCount = FoundCount;
1596 }
1597
1598 if (Entries == NULL) {
1599 goto CLEAN_EXIT;
1600 }
1601
1602 //
1603 // Allocate buffer to copy the found entries.
1604 //
1605 FindData = AllocatePool (FoundCount * FoundEntryLength);
1606 if (FindData == NULL) {
1607 DEBUG ((EFI_D_ERROR, "ArpFindCacheEntry: Failed to allocate memory.\n"));
1608 Status = EFI_OUT_OF_RESOURCES;
1609 goto CLEAN_EXIT;
1610 }
1611
1612 //
1613 // Return the address to the user.
1614 //
1615 *Entries = FindData;
1616
1617 //
1618 // Dump the entries.
1619 //
1620 while (!NetMapIsEmpty (&FoundEntries)) {
1621 //
1622 // Get a cache entry from the map.
1623 //
1624 CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);
1625
1626 //
1627 // Set the fields in FindData.
1628 //
1629 FindData->Size = FoundEntryLength;
1630 FindData->DenyFlag = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);
1631 FindData->StaticFlag = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);
1632 FindData->HwAddressType = ArpService->SnpMode.IfType;
1633 FindData->SwAddressType = Instance->ConfigData.SwAddressType;
1634 FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;
1635 FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;
1636
1637 //
1638 // Copy the software address.
1639 //
1640 CopyMem (
1641 FindData + 1,
1642 CacheEntry->Addresses[Protocol].AddressPtr,
1643 FindData->SwAddressLength
1644 );
1645
1646 //
1647 // Copy the hardware address.
1648 //
1649 CopyMem (
1650 (UINT8 *)(FindData + 1) + FindData->SwAddressLength,
1651 CacheEntry->Addresses[Hardware].AddressPtr,
1652 FindData->HwAddressLength
1653 );
1654
1655 //
1656 // Slip to the next FindData.
1657 //
1658 FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + FoundEntryLength);
1659 }
1660
1661 CLEAN_EXIT:
1662
1663 NetMapClean (&FoundEntries);
1664
1665 return Status;
1666 }
1667