Home | History | Annotate | Download | only in ArpDxe
      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
     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
    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
    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
    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
    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
    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
    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