1 /** @file
2   Implementation of EFI Address Resolution Protocol (ARP) Protocol interface functions.
3 
4 Copyright (c) 2006 - 2009, 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
9 
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.
12 
13 **/
14 
15 #include "ArpImpl.h"
16 
17 
18 /**
19   This function is used to assign a station address to the ARP cache for this instance
20   of the ARP driver.
21 
22   Each ARP instance has one station address. The EFI_ARP_PROTOCOL driver will
23   respond to ARP requests that match this registered station address. A call to
24   this function with the ConfigData field set to NULL will reset this ARP instance.
25 
26   Once a protocol type and station address have been assigned to this ARP instance,
27   all the following ARP functions will use this information. Attempting to change
28   the protocol type or station address to a configured ARP instance will result in errors.
29 
30   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
31   @param  ConfigData             Pointer to the EFI_ARP_CONFIG_DATA structure.
32 
33   @retval EFI_SUCCESS            The new station address was successfully
34                                  registered.
35   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
36                                  This is NULL. SwAddressLength is zero when
37                                  ConfigData is not NULL. StationAddress is NULL
38                                  when ConfigData is not NULL.
39   @retval EFI_ACCESS_DENIED      The SwAddressType, SwAddressLength, or
40                                  StationAddress is different from the one that is
41                                  already registered.
42   @retval EFI_OUT_OF_RESOURCES   Storage for the new StationAddress could not be
43                                  allocated.
44 
45 **/
46 EFI_STATUS
47 EFIAPI
ArpConfigure(IN EFI_ARP_PROTOCOL * This,IN EFI_ARP_CONFIG_DATA * ConfigData OPTIONAL)48 ArpConfigure (
49   IN EFI_ARP_PROTOCOL     *This,
50   IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL
51   )
52 {
53   EFI_STATUS         Status;
54   ARP_INSTANCE_DATA  *Instance;
55   EFI_TPL            OldTpl;
56 
57   if (This == NULL) {
58     return EFI_INVALID_PARAMETER;
59   }
60 
61   if ((ConfigData != NULL) &&
62     ((ConfigData->SwAddressLength == 0) ||
63     (ConfigData->StationAddress == NULL) ||
64     (ConfigData->SwAddressType <= 1500))) {
65     return EFI_INVALID_PARAMETER;
66   }
67 
68   Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
69 
70   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
71 
72   //
73   // Configure this instance, the ConfigData has already passed the basic checks.
74   //
75   Status = ArpConfigureInstance (Instance, ConfigData);
76 
77   gBS->RestoreTPL (OldTpl);
78 
79   return Status;
80 }
81 
82 
83 /**
84   This function is used to insert entries into the ARP cache.
85 
86   ARP cache entries are typically inserted and updated by network protocol drivers
87   as network traffic is processed. Most ARP cache entries will time out and be
88   deleted if the network traffic stops. ARP cache entries that were inserted
89   by the Add() function may be static (will not time out) or dynamic (will time out).
90   Default ARP cache timeout values are not covered in most network protocol
91   specifications (although RFC 1122 comes pretty close) and will only be
92   discussed in general in this specification. The timeout values that are
93   used in the EFI Sample Implementation should be used only as a guideline.
94   Final product implementations of the EFI network stack should be tuned for
95   their expected network environments.
96 
97   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
98   @param  DenyFlag               Set to TRUE if this entry is a deny entry. Set to
99                                  FALSE if this  entry is a normal entry.
100   @param  TargetSwAddress        Pointer to a protocol address to add (or deny).
101                                  May be set to NULL if DenyFlag is TRUE.
102   @param  TargetHwAddress        Pointer to a hardware address to add (or deny).
103                                  May be set to NULL if DenyFlag is TRUE.
104   @param  TimeoutValue           Time in 100-ns units that this entry will remain
105                                  in the ARP cache. A value of zero means that the
106                                  entry is permanent. A nonzero value will override
107                                  the one given by Configure() if the entry to be
108                                  added is a dynamic entry.
109   @param  Overwrite              If TRUE, the matching cache entry will be
110                                  overwritten with the supplied parameters. If
111                                  FALSE, EFI_ACCESS_DENIED is returned if the
112                                  corresponding cache entry already exists.
113 
114   @retval EFI_SUCCESS            The entry has been added or updated.
115   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
116                                  This is NULL. DenyFlag is FALSE and
117                                  TargetHwAddress is NULL. DenyFlag is FALSE and
118                                  TargetSwAddress is NULL. TargetHwAddress is NULL
119                                  and TargetSwAddress is NULL. Both TargetSwAddress
120                                  and TargetHwAddress are not NULL when DenyFlag is
121                                  TRUE.
122   @retval EFI_OUT_OF_RESOURCES   The new ARP cache entry could not be allocated.
123   @retval EFI_ACCESS_DENIED      The ARP cache entry already exists and Overwrite
124                                  is not true.
125   @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.
126 
127 **/
128 EFI_STATUS
129 EFIAPI
ArpAdd(IN EFI_ARP_PROTOCOL * This,IN BOOLEAN DenyFlag,IN VOID * TargetSwAddress OPTIONAL,IN VOID * TargetHwAddress OPTIONAL,IN UINT32 TimeoutValue,IN BOOLEAN Overwrite)130 ArpAdd (
131   IN EFI_ARP_PROTOCOL  *This,
132   IN BOOLEAN           DenyFlag,
133   IN VOID              *TargetSwAddress OPTIONAL,
134   IN VOID              *TargetHwAddress OPTIONAL,
135   IN UINT32            TimeoutValue,
136   IN BOOLEAN           Overwrite
137   )
138 {
139   EFI_STATUS               Status;
140   ARP_INSTANCE_DATA        *Instance;
141   ARP_SERVICE_DATA         *ArpService;
142   ARP_CACHE_ENTRY          *CacheEntry;
143   EFI_SIMPLE_NETWORK_MODE  *SnpMode;
144   NET_ARP_ADDRESS          MatchAddress[2];
145   EFI_TPL                  OldTpl;
146 
147   if (This == NULL) {
148     return EFI_INVALID_PARAMETER;
149   }
150 
151   if (((!DenyFlag) && ((TargetHwAddress == NULL) || (TargetSwAddress == NULL))) ||
152     (DenyFlag && (TargetHwAddress != NULL) && (TargetSwAddress != NULL)) ||
153     ((TargetHwAddress == NULL) && (TargetSwAddress == NULL))) {
154     return EFI_INVALID_PARAMETER;
155   }
156 
157   Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
158 
159   if (!Instance->Configured) {
160     return EFI_NOT_STARTED;
161   }
162 
163   Status     = EFI_SUCCESS;
164   ArpService = Instance->ArpService;
165   SnpMode    = &Instance->ArpService->SnpMode;
166 
167   //
168   // Fill the hardware address part in the MatchAddress.
169   //
170   MatchAddress[Hardware].Type       = SnpMode->IfType;
171   MatchAddress[Hardware].Length     = (UINT8) SnpMode->HwAddressSize;
172   MatchAddress[Hardware].AddressPtr = TargetHwAddress;
173 
174   //
175   // Fill the software address part in the MatchAddress.
176   //
177   MatchAddress[Protocol].Type       = Instance->ConfigData.SwAddressType;
178   MatchAddress[Protocol].Length     = Instance->ConfigData.SwAddressLength;
179   MatchAddress[Protocol].AddressPtr = TargetSwAddress;
180 
181   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
182 
183   //
184   // See whether the entry to add exists. Check the DeinedCacheTable first.
185   //
186   CacheEntry = ArpFindDeniedCacheEntry (
187                  ArpService,
188                  &MatchAddress[Protocol],
189                  &MatchAddress[Hardware]
190                  );
191 
192   if (CacheEntry == NULL) {
193     //
194     // Check the ResolvedCacheTable
195     //
196     CacheEntry = ArpFindNextCacheEntryInTable (
197                    &ArpService->ResolvedCacheTable,
198                    NULL,
199                    ByBoth,
200                    &MatchAddress[Protocol],
201                    &MatchAddress[Hardware]
202                    );
203   }
204 
205   if ((CacheEntry != NULL) && !Overwrite) {
206     //
207     // The entry to add exists, if not Overwirte, deny this add request.
208     //
209     Status = EFI_ACCESS_DENIED;
210     goto UNLOCK_EXIT;
211   }
212 
213   if ((CacheEntry == NULL) && (TargetSwAddress != NULL)) {
214     //
215     // Check whether there are pending requests matching the entry to be added.
216     //
217     CacheEntry = ArpFindNextCacheEntryInTable (
218                    &ArpService->PendingRequestTable,
219                    NULL,
220                    ByProtoAddress,
221                    &MatchAddress[Protocol],
222                    NULL
223                    );
224   }
225 
226   if (CacheEntry != NULL) {
227     //
228     // Remove it from the Table.
229     //
230     RemoveEntryList (&CacheEntry->List);
231   } else {
232     //
233     // It's a new entry, allocate memory for the entry.
234     //
235     CacheEntry = ArpAllocCacheEntry (Instance);
236 
237     if (CacheEntry == NULL) {
238       DEBUG ((EFI_D_ERROR, "ArpAdd: Failed to allocate pool for CacheEntry.\n"));
239       Status = EFI_OUT_OF_RESOURCES;
240       goto UNLOCK_EXIT;
241     }
242   }
243 
244   //
245   // Overwrite these parameters.
246   //
247   CacheEntry->DefaultDecayTime = TimeoutValue;
248   CacheEntry->DecayTime        = TimeoutValue;
249 
250   //
251   // Fill in the addresses.
252   //
253   ArpFillAddressInCacheEntry (
254     CacheEntry,
255     &MatchAddress[Hardware],
256     &MatchAddress[Protocol]
257     );
258 
259   //
260   // Inform the user if there is any.
261   //
262   ArpAddressResolved (CacheEntry, NULL, NULL);
263 
264   //
265   // Add this CacheEntry to the corresponding CacheTable.
266   //
267   if (DenyFlag) {
268     InsertHeadList (&ArpService->DeniedCacheTable, &CacheEntry->List);
269   } else {
270     InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);
271   }
272 
273 UNLOCK_EXIT:
274 
275   gBS->RestoreTPL (OldTpl);
276 
277   return Status;
278 }
279 
280 
281 /**
282   This function searches the ARP cache for matching entries and allocates a buffer into
283   which those entries are copied.
284 
285   The first part of the allocated buffer is EFI_ARP_FIND_DATA, following which
286   are protocol address pairs and hardware address pairs.
287   When finding a specific protocol address (BySwAddress is TRUE and AddressBuffer
288   is not NULL), the ARP cache timeout for the found entry is reset if Refresh is
289   set to TRUE. If the found ARP cache entry is a permanent entry, it is not
290   affected by Refresh.
291 
292   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
293   @param  BySwAddress            Set to TRUE to look for matching software protocol
294                                  addresses. Set to FALSE to look for matching
295                                  hardware protocol addresses.
296   @param  AddressBuffer          Pointer to address buffer. Set to NULL to match
297                                  all addresses.
298   @param  EntryLength            The size of an entry in the entries buffer.
299   @param  EntryCount             The number of ARP cache entries that are found by
300                                  the specified criteria.
301   @param  Entries                Pointer to the buffer that will receive the ARP
302                                  cache entries.
303   @param  Refresh                Set to TRUE to refresh the timeout value of the
304                                  matching ARP cache entry.
305 
306   @retval EFI_SUCCESS            The requested ARP cache entries were copied into
307                                  the buffer.
308   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
309                                  This is NULL. Both EntryCount and EntryLength are
310                                  NULL, when Refresh is FALSE.
311   @retval EFI_NOT_FOUND          No matching entries were found.
312   @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.
313 
314 **/
315 EFI_STATUS
316 EFIAPI
ArpFind(IN EFI_ARP_PROTOCOL * This,IN BOOLEAN BySwAddress,IN VOID * AddressBuffer OPTIONAL,OUT UINT32 * EntryLength OPTIONAL,OUT UINT32 * EntryCount OPTIONAL,OUT EFI_ARP_FIND_DATA ** Entries OPTIONAL,IN BOOLEAN Refresh)317 ArpFind (
318   IN EFI_ARP_PROTOCOL    *This,
319   IN BOOLEAN             BySwAddress,
320   IN VOID                *AddressBuffer OPTIONAL,
321   OUT UINT32             *EntryLength   OPTIONAL,
322   OUT UINT32             *EntryCount    OPTIONAL,
323   OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,
324   IN BOOLEAN             Refresh
325   )
326 {
327   EFI_STATUS         Status;
328   ARP_INSTANCE_DATA  *Instance;
329   EFI_TPL            OldTpl;
330 
331   if ((This == NULL) ||
332     (!Refresh && (EntryCount == NULL) && (EntryLength == NULL)) ||
333     ((Entries != NULL) && ((EntryLength == NULL) || (EntryCount == NULL)))) {
334     return EFI_INVALID_PARAMETER;
335   }
336 
337   Instance   = ARP_INSTANCE_DATA_FROM_THIS (This);
338 
339   if (!Instance->Configured) {
340     return EFI_NOT_STARTED;
341   }
342 
343   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
344 
345   //
346   // All the check passed, find the cache entries now.
347   //
348   Status = ArpFindCacheEntry (
349              Instance,
350              BySwAddress,
351              AddressBuffer,
352              EntryLength,
353              EntryCount,
354              Entries,
355              Refresh
356              );
357 
358   gBS->RestoreTPL (OldTpl);
359 
360   return Status;
361 }
362 
363 
364 /**
365   This function removes specified ARP cache entries.
366 
367   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
368   @param  BySwAddress            Set to TRUE to delete matching protocol addresses.
369                                  Set to FALSE to delete matching hardware
370                                  addresses.
371   @param  AddressBuffer          Pointer to the address buffer that is used as a
372                                  key to look for the cache entry. Set to NULL to
373                                  delete all entries.
374 
375   @retval EFI_SUCCESS            The entry was removed from the ARP cache.
376   @retval EFI_INVALID_PARAMETER  This is NULL.
377   @retval EFI_NOT_FOUND          The specified deletion key was not found.
378   @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.
379 
380 **/
381 EFI_STATUS
382 EFIAPI
ArpDelete(IN EFI_ARP_PROTOCOL * This,IN BOOLEAN BySwAddress,IN VOID * AddressBuffer OPTIONAL)383 ArpDelete (
384   IN EFI_ARP_PROTOCOL  *This,
385   IN BOOLEAN           BySwAddress,
386   IN VOID              *AddressBuffer OPTIONAL
387   )
388 {
389   ARP_INSTANCE_DATA  *Instance;
390   UINTN              Count;
391   EFI_TPL            OldTpl;
392 
393   if (This == NULL) {
394     return EFI_INVALID_PARAMETER;
395   }
396 
397   Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
398 
399   if (!Instance->Configured) {
400     return EFI_NOT_STARTED;
401   }
402 
403   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
404 
405   //
406   // Delete the specified cache entries.
407   //
408   Count = ArpDeleteCacheEntry (Instance, BySwAddress, AddressBuffer, TRUE);
409 
410   gBS->RestoreTPL (OldTpl);
411 
412   return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
413 }
414 
415 
416 /**
417   This function delete all dynamic entries from the ARP cache that match the specified
418   software protocol type.
419 
420   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
421 
422   @retval EFI_SUCCESS            The cache has been flushed.
423   @retval EFI_INVALID_PARAMETER  This is NULL.
424   @retval EFI_NOT_FOUND          There are no matching dynamic cache entries.
425   @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.
426 
427 **/
428 EFI_STATUS
429 EFIAPI
ArpFlush(IN EFI_ARP_PROTOCOL * This)430 ArpFlush (
431   IN EFI_ARP_PROTOCOL  *This
432   )
433 {
434   ARP_INSTANCE_DATA  *Instance;
435   UINTN              Count;
436   EFI_TPL            OldTpl;
437 
438   if (This == NULL) {
439     return EFI_INVALID_PARAMETER;
440   }
441 
442   Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
443 
444   if (!Instance->Configured) {
445     return EFI_NOT_STARTED;
446   }
447 
448   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
449 
450   //
451   // Delete the dynamic entries from the cache table.
452   //
453   Count = ArpDeleteCacheEntry (Instance, FALSE, NULL, FALSE);
454 
455   gBS->RestoreTPL (OldTpl);
456 
457   return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
458 }
459 
460 
461 /**
462   This function tries to resolve the TargetSwAddress and optionally returns a
463   TargetHwAddress if it already exists in the ARP cache.
464 
465   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
466   @param  TargetSwAddress        Pointer to the protocol address to resolve.
467   @param  ResolvedEvent          Pointer to the event that will be signaled when
468                                  the address is resolved or some error occurs.
469   @param  TargetHwAddress        Pointer to the buffer for the resolved hardware
470                                  address in network byte order.
471 
472   @retval EFI_SUCCESS            The data is copied from the ARP cache into the
473                                  TargetHwAddress buffer.
474   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
475                                  This is NULL. TargetHwAddress is NULL.
476   @retval EFI_ACCESS_DENIED      The requested address is not present in the normal
477                                  ARP cache but is present in the deny address list.
478                                  Outgoing traffic to that address is forbidden.
479   @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.
480   @retval EFI_NOT_READY          The request has been started and is not finished.
481 
482 **/
483 EFI_STATUS
484 EFIAPI
ArpRequest(IN EFI_ARP_PROTOCOL * This,IN VOID * TargetSwAddress OPTIONAL,IN EFI_EVENT ResolvedEvent OPTIONAL,OUT VOID * TargetHwAddress)485 ArpRequest (
486   IN EFI_ARP_PROTOCOL  *This,
487   IN VOID              *TargetSwAddress OPTIONAL,
488   IN EFI_EVENT         ResolvedEvent    OPTIONAL,
489   OUT VOID             *TargetHwAddress
490   )
491 {
492   EFI_STATUS               Status;
493   ARP_INSTANCE_DATA        *Instance;
494   ARP_SERVICE_DATA         *ArpService;
495   EFI_SIMPLE_NETWORK_MODE  *SnpMode;
496   ARP_CACHE_ENTRY          *CacheEntry;
497   NET_ARP_ADDRESS          HardwareAddress;
498   NET_ARP_ADDRESS          ProtocolAddress;
499   USER_REQUEST_CONTEXT     *RequestContext;
500   EFI_TPL                  OldTpl;
501 
502   if ((This == NULL) || (TargetHwAddress == NULL)) {
503     return EFI_INVALID_PARAMETER;
504   }
505 
506   Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
507 
508   if (!Instance->Configured) {
509     return EFI_NOT_STARTED;
510   }
511 
512   Status     = EFI_SUCCESS;
513   ArpService = Instance->ArpService;
514   SnpMode    = &ArpService->SnpMode;
515 
516   if ((TargetSwAddress == NULL) ||
517     ((Instance->ConfigData.SwAddressType == IPV4_ETHER_PROTO_TYPE) &&
518     IP4_IS_LOCAL_BROADCAST (*((UINT32 *)TargetSwAddress)))) {
519     //
520     // Return the hardware broadcast address.
521     //
522     CopyMem (TargetHwAddress, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
523 
524     goto SIGNAL_USER;
525   }
526 
527   if ((Instance->ConfigData.SwAddressType == IPV4_ETHER_PROTO_TYPE) &&
528     IP4_IS_MULTICAST (NTOHL (*((UINT32 *)TargetSwAddress)))) {
529     //
530     // If the software address is an IPv4 multicast address, invoke Mnp to
531     // resolve the address.
532     //
533     Status = ArpService->Mnp->McastIpToMac (
534                                 ArpService->Mnp,
535                                 FALSE,
536                                 TargetSwAddress,
537                                 TargetHwAddress
538                                 );
539     goto SIGNAL_USER;
540   }
541 
542   HardwareAddress.Type       = SnpMode->IfType;
543   HardwareAddress.Length     = (UINT8)SnpMode->HwAddressSize;
544   HardwareAddress.AddressPtr = NULL;
545 
546   ProtocolAddress.Type       = Instance->ConfigData.SwAddressType;
547   ProtocolAddress.Length     = Instance->ConfigData.SwAddressLength;
548   ProtocolAddress.AddressPtr = TargetSwAddress;
549 
550   //
551   // Initialize the TargetHwAddrss to a zero address.
552   //
553   ZeroMem (TargetHwAddress, SnpMode->HwAddressSize);
554 
555   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
556 
557   //
558   // Check whether the software address is in the denied table.
559   //
560   CacheEntry = ArpFindDeniedCacheEntry (ArpService, &ProtocolAddress, NULL);
561   if (CacheEntry != NULL) {
562     Status = EFI_ACCESS_DENIED;
563     goto UNLOCK_EXIT;
564   }
565 
566   //
567   // Check whether the software address is already resolved.
568   //
569   CacheEntry = ArpFindNextCacheEntryInTable (
570                  &ArpService->ResolvedCacheTable,
571                  NULL,
572                  ByProtoAddress,
573                  &ProtocolAddress,
574                  NULL
575                  );
576   if (CacheEntry != NULL) {
577     //
578     // Resolved, copy the address into the user buffer.
579     //
580     CopyMem (
581       TargetHwAddress,
582       CacheEntry->Addresses[Hardware].AddressPtr,
583       CacheEntry->Addresses[Hardware].Length
584       );
585 
586     goto UNLOCK_EXIT;
587   }
588 
589   if (ResolvedEvent == NULL) {
590     Status = EFI_NOT_READY;
591     goto UNLOCK_EXIT;
592   }
593 
594   //
595   // Create a request context for this arp request.
596   //
597   RequestContext = AllocatePool (sizeof(USER_REQUEST_CONTEXT));
598   if (RequestContext == NULL) {
599     DEBUG ((EFI_D_ERROR, "ArpRequest: Allocate memory for RequestContext failed.\n"));
600 
601     Status = EFI_OUT_OF_RESOURCES;
602     goto UNLOCK_EXIT;
603   }
604 
605   RequestContext->Instance         = Instance;
606   RequestContext->UserRequestEvent = ResolvedEvent;
607   RequestContext->UserHwAddrBuffer = TargetHwAddress;
608   InitializeListHead (&RequestContext->List);
609 
610   //
611   // Check whether there is a same request.
612   //
613   CacheEntry = ArpFindNextCacheEntryInTable (
614                  &ArpService->PendingRequestTable,
615                  NULL,
616                  ByProtoAddress,
617                  &ProtocolAddress,
618                  NULL
619                  );
620   if (CacheEntry != NULL) {
621 
622     CacheEntry->NextRetryTime = Instance->ConfigData.RetryTimeOut;
623     CacheEntry->RetryCount    = Instance->ConfigData.RetryCount;
624   } else {
625     //
626     // Allocate a cache entry for this request.
627     //
628     CacheEntry = ArpAllocCacheEntry (Instance);
629     if (CacheEntry == NULL) {
630       DEBUG ((EFI_D_ERROR, "ArpRequest: Allocate memory for CacheEntry failed.\n"));
631       FreePool (RequestContext);
632 
633       Status = EFI_OUT_OF_RESOURCES;
634       goto UNLOCK_EXIT;
635     }
636 
637     //
638     // Fill the software address.
639     //
640     ArpFillAddressInCacheEntry (CacheEntry, &HardwareAddress, &ProtocolAddress);
641 
642     //
643     // Add this entry into the PendingRequestTable.
644     //
645     InsertTailList (&ArpService->PendingRequestTable, &CacheEntry->List);
646   }
647 
648   //
649   // Link this request context into the cache entry.
650   //
651   InsertHeadList (&CacheEntry->UserRequestList, &RequestContext->List);
652 
653   //
654   // Send out the ARP Request frame.
655   //
656   ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REQUEST);
657   Status = EFI_NOT_READY;
658 
659 UNLOCK_EXIT:
660 
661   gBS->RestoreTPL (OldTpl);
662 
663 SIGNAL_USER:
664 
665   if ((ResolvedEvent != NULL) && (Status == EFI_SUCCESS)) {
666     gBS->SignalEvent (ResolvedEvent);
667 
668     //
669     // Dispatch the DPC queued by the NotifyFunction of ResolvedEvent.
670     //
671     DispatchDpc ();
672   }
673 
674   return Status;
675 }
676 
677 
678 /**
679   This function aborts the previous ARP request (identified by This,  TargetSwAddress
680   and ResolvedEvent) that is issued by EFI_ARP_PROTOCOL.Request().
681 
682   If the request is in the internal ARP request queue, the request is aborted
683   immediately and its ResolvedEvent is signaled. Only an asynchronous address
684   request needs to be canceled. If TargeSwAddress and ResolveEvent are both
685   NULL, all the pending asynchronous requests that have been issued by This
686   instance will be cancelled and their corresponding events will be signaled.
687 
688   @param  This                   Pointer to the EFI_ARP_PROTOCOL instance.
689   @param  TargetSwAddress        Pointer to the protocol address in previous
690                                  request session.
691   @param  ResolvedEvent          Pointer to the event that is used as the
692                                  notification event in previous request session.
693 
694   @retval EFI_SUCCESS            The pending request session(s) is/are aborted and
695                                  corresponding event(s) is/are signaled.
696   @retval EFI_INVALID_PARAMETER  One or more of the following conditions is TRUE:
697                                  This is NULL. TargetSwAddress is not NULL and
698                                  ResolvedEvent is NULL. TargetSwAddress is NULL and
699                                  ResolvedEvent is not NULL.
700   @retval EFI_NOT_STARTED        The ARP driver instance has not been configured.
701   @retval EFI_NOT_FOUND          The request is not issued by
702                                  EFI_ARP_PROTOCOL.Request().
703 
704 **/
705 EFI_STATUS
706 EFIAPI
ArpCancel(IN EFI_ARP_PROTOCOL * This,IN VOID * TargetSwAddress OPTIONAL,IN EFI_EVENT ResolvedEvent OPTIONAL)707 ArpCancel (
708   IN EFI_ARP_PROTOCOL  *This,
709   IN VOID              *TargetSwAddress OPTIONAL,
710   IN EFI_EVENT         ResolvedEvent    OPTIONAL
711   )
712 {
713   ARP_INSTANCE_DATA  *Instance;
714   UINTN              Count;
715   EFI_TPL            OldTpl;
716 
717   if ((This == NULL) ||
718     ((TargetSwAddress != NULL) && (ResolvedEvent == NULL)) ||
719     ((TargetSwAddress == NULL) && (ResolvedEvent != NULL))) {
720     return EFI_INVALID_PARAMETER;
721   }
722 
723   Instance = ARP_INSTANCE_DATA_FROM_THIS (This);
724 
725   if (!Instance->Configured) {
726     return EFI_NOT_STARTED;
727   }
728 
729   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
730 
731   //
732   // Cancel the specified request.
733   //
734   Count = ArpCancelRequest (Instance, TargetSwAddress, ResolvedEvent);
735 
736   //
737   // Dispatch the DPCs queued by the NotifyFunction of the events signaled
738   // by ArpCancleRequest.
739   //
740   DispatchDpc ();
741 
742   gBS->RestoreTPL (OldTpl);
743 
744   return (Count == 0) ? EFI_NOT_FOUND : EFI_SUCCESS;
745 }
746