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