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