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