Home | History | Annotate | Download | only in ArpDxe
      1 /** @file
      2   The implementation of the ARP protocol.
      3 
      4 Copyright (c) 2006 - 2012, 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 // Global variable of EFI ARP Protocol Interface.
     19 //
     20 EFI_ARP_PROTOCOL  mEfiArpProtocolTemplate = {
     21   ArpConfigure,
     22   ArpAdd,
     23   ArpFind,
     24   ArpDelete,
     25   ArpFlush,
     26   ArpRequest,
     27   ArpCancel
     28 };
     29 
     30 
     31 /**
     32   Initialize the instance context data.
     33 
     34   @param[in]   ArpService        Pointer to the arp service context data this
     35                                  instance belongs to.
     36   @param[out]  Instance          Pointer to the instance context data.
     37 
     38   @return None.
     39 
     40 **/
     41 VOID
     42 ArpInitInstance (
     43   IN  ARP_SERVICE_DATA   *ArpService,
     44   OUT ARP_INSTANCE_DATA  *Instance
     45   )
     46 {
     47   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
     48 
     49   Instance->Signature  = ARP_INSTANCE_DATA_SIGNATURE;
     50   Instance->ArpService = ArpService;
     51 
     52   CopyMem (&Instance->ArpProto, &mEfiArpProtocolTemplate, sizeof (Instance->ArpProto));
     53 
     54   Instance->Configured = FALSE;
     55   Instance->InDestroy  = FALSE;
     56 
     57   InitializeListHead (&Instance->List);
     58 }
     59 
     60 
     61 /**
     62   Process the Arp packets received from Mnp, the procedure conforms to RFC826.
     63 
     64   @param[in]  Context            Pointer to the context data registerd to the
     65                                  Event.
     66 
     67   @return None.
     68 
     69 **/
     70 VOID
     71 EFIAPI
     72 ArpOnFrameRcvdDpc (
     73   IN VOID       *Context
     74   )
     75 {
     76   EFI_STATUS                            Status;
     77   ARP_SERVICE_DATA                      *ArpService;
     78   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *RxToken;
     79   EFI_MANAGED_NETWORK_RECEIVE_DATA      *RxData;
     80   ARP_HEAD                              *Head;
     81   ARP_ADDRESS                           ArpAddress;
     82   ARP_CACHE_ENTRY                       *CacheEntry;
     83   LIST_ENTRY                            *Entry;
     84   ARP_INSTANCE_DATA                     *Instance;
     85   EFI_ARP_CONFIG_DATA                   *ConfigData;
     86   NET_ARP_ADDRESS                       SenderAddress[2];
     87   BOOLEAN                               ProtoMatched;
     88   BOOLEAN                               IsTarget;
     89   BOOLEAN                               MergeFlag;
     90 
     91   ArpService = (ARP_SERVICE_DATA *)Context;
     92   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
     93 
     94   RxToken = &ArpService->RxToken;
     95 
     96   if (RxToken->Status == EFI_ABORTED) {
     97     //
     98     // The Token is aborted, possibly by arp itself, just return and the receiving
     99     // process is stopped.
    100     //
    101     return;
    102   }
    103 
    104   if (EFI_ERROR (RxToken->Status)) {
    105     //
    106     // Restart the receiving if any other error Status occurs.
    107     //
    108     goto RESTART_RECEIVE;
    109   }
    110 
    111   //
    112   // Status is EFI_SUCCESS, process the received frame.
    113   //
    114   RxData = RxToken->Packet.RxData;
    115   Head   = (ARP_HEAD *) RxData->PacketData;
    116 
    117   //
    118   // Convert the byte order of the multi-byte fields.
    119   //
    120   Head->HwType    = NTOHS (Head->HwType);
    121   Head->ProtoType = NTOHS (Head->ProtoType);
    122   Head->OpCode    = NTOHS (Head->OpCode);
    123 
    124   if ((Head->HwType != ArpService->SnpMode.IfType) ||
    125     (Head->HwAddrLen != ArpService->SnpMode.HwAddressSize) ||
    126     (RxData->ProtocolType != ARP_ETHER_PROTO_TYPE)) {
    127     //
    128     // The hardware type or the hardware address length doesn't match.
    129     // There is a sanity check for the protocol type too.
    130     //
    131     goto RECYCLE_RXDATA;
    132   }
    133 
    134   //
    135   // Set the pointers to the addresses contained in the arp packet.
    136   //
    137   ArpAddress.SenderHwAddr    = (UINT8 *)(Head + 1);
    138   ArpAddress.SenderProtoAddr = ArpAddress.SenderHwAddr + Head->HwAddrLen;
    139   ArpAddress.TargetHwAddr    = ArpAddress.SenderProtoAddr + Head->ProtoAddrLen;
    140   ArpAddress.TargetProtoAddr = ArpAddress.TargetHwAddr + Head->HwAddrLen;
    141 
    142   SenderAddress[Hardware].Type       = Head->HwType;
    143   SenderAddress[Hardware].Length     = Head->HwAddrLen;
    144   SenderAddress[Hardware].AddressPtr = ArpAddress.SenderHwAddr;
    145 
    146   SenderAddress[Protocol].Type       = Head->ProtoType;
    147   SenderAddress[Protocol].Length     = Head->ProtoAddrLen;
    148   SenderAddress[Protocol].AddressPtr = ArpAddress.SenderProtoAddr;
    149 
    150   //
    151   // First, check the denied cache table.
    152   //
    153   CacheEntry = ArpFindDeniedCacheEntry (
    154                  ArpService,
    155                  &SenderAddress[Protocol],
    156                  &SenderAddress[Hardware]
    157                  );
    158   if (CacheEntry != NULL) {
    159     //
    160     // This address (either hardware or protocol address, or both) is configured to
    161     // be a deny entry, silently skip the normal process.
    162     //
    163     goto RECYCLE_RXDATA;
    164   }
    165 
    166   ProtoMatched = FALSE;
    167   IsTarget     = FALSE;
    168   Instance     = NULL;
    169   NET_LIST_FOR_EACH (Entry, &ArpService->ChildrenList) {
    170     //
    171     // Iterate all the children.
    172     //
    173     Instance = NET_LIST_USER_STRUCT (Entry, ARP_INSTANCE_DATA, List);
    174     NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
    175     ConfigData = &Instance->ConfigData;
    176 
    177     if ((Instance->Configured) &&
    178       (Head->ProtoType == ConfigData->SwAddressType) &&
    179       (Head->ProtoAddrLen == ConfigData->SwAddressLength)) {
    180       //
    181       // The protocol type is matched for the received arp packet.
    182       //
    183       ProtoMatched = TRUE;
    184       if (0 == CompareMem (
    185                  (VOID *)ArpAddress.TargetProtoAddr,
    186                  ConfigData->StationAddress,
    187                  ConfigData->SwAddressLength
    188                  )) {
    189         //
    190         // The arp driver has the target address required by the received arp packet.
    191         //
    192         IsTarget = TRUE;
    193         break;
    194       }
    195     }
    196   }
    197 
    198   if (!ProtoMatched) {
    199     //
    200     // Protocol type unmatchable, skip.
    201     //
    202     goto RECYCLE_RXDATA;
    203   }
    204 
    205   //
    206   // Check whether the sender's address information is already in the cache.
    207   //
    208   MergeFlag  = FALSE;
    209   CacheEntry = ArpFindNextCacheEntryInTable (
    210                  &ArpService->ResolvedCacheTable,
    211                  NULL,
    212                  ByProtoAddress,
    213                  &SenderAddress[Protocol],
    214                  NULL
    215                  );
    216   if (CacheEntry != NULL) {
    217     //
    218     // Update the entry with the new information.
    219     //
    220     ArpFillAddressInCacheEntry (CacheEntry, &SenderAddress[Hardware], NULL);
    221     CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
    222     MergeFlag = TRUE;
    223   }
    224 
    225   if (!IsTarget) {
    226     //
    227     // This arp packet isn't targeted to us, skip now.
    228     //
    229     goto RECYCLE_RXDATA;
    230   }
    231 
    232   if (!MergeFlag) {
    233     //
    234     // Add the triplet <protocol type, sender protocol address, sender hardware address>
    235     // to the translation table.
    236     //
    237     CacheEntry = ArpFindNextCacheEntryInTable (
    238                    &ArpService->PendingRequestTable,
    239                    NULL,
    240                    ByProtoAddress,
    241                    &SenderAddress[Protocol],
    242                    NULL
    243                    );
    244     if (CacheEntry == NULL) {
    245       //
    246       // Allocate a new CacheEntry.
    247       //
    248       CacheEntry = ArpAllocCacheEntry (NULL);
    249       if (CacheEntry == NULL) {
    250         goto RECYCLE_RXDATA;
    251       }
    252     }
    253 
    254     if (!IsListEmpty (&CacheEntry->List)) {
    255       RemoveEntryList (&CacheEntry->List);
    256     }
    257 
    258     //
    259     // Fill the addresses into the CacheEntry.
    260     //
    261     ArpFillAddressInCacheEntry (
    262       CacheEntry,
    263       &SenderAddress[Hardware],
    264       &SenderAddress[Protocol]
    265       );
    266 
    267     //
    268     // Inform the user.
    269     //
    270     ArpAddressResolved (CacheEntry, NULL, NULL);
    271 
    272     //
    273     // Add this entry into the ResolvedCacheTable
    274     //
    275     InsertHeadList (&ArpService->ResolvedCacheTable, &CacheEntry->List);
    276   }
    277 
    278   if (Head->OpCode == ARP_OPCODE_REQUEST) {
    279     //
    280     // Send back the ARP Reply. If we reach here, Instance is not NULL and CacheEntry
    281     // is not NULL.
    282     //
    283     ArpSendFrame (Instance, CacheEntry, ARP_OPCODE_REPLY);
    284   }
    285 
    286 RECYCLE_RXDATA:
    287 
    288   //
    289   // Signal Mnp to recycle the RxData.
    290   //
    291   gBS->SignalEvent (RxData->RecycleEvent);
    292 
    293 RESTART_RECEIVE:
    294 
    295   //
    296   // Continue to receive packets from Mnp.
    297   //
    298   Status = ArpService->Mnp->Receive (ArpService->Mnp, RxToken);
    299 
    300   DEBUG_CODE (
    301     if (EFI_ERROR (Status)) {
    302       DEBUG ((EFI_D_ERROR, "ArpOnFrameRcvd: ArpService->Mnp->Receive "
    303         "failed, %r\n.", Status));
    304     }
    305   );
    306 }
    307 
    308 /**
    309   Queue ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK.
    310 
    311   @param[in]  Event                  The Event this notify function registered to.
    312   @param[in]  Context                Pointer to the context data registerd to the
    313                                      Event.
    314 
    315   @return None.
    316 
    317 **/
    318 VOID
    319 EFIAPI
    320 ArpOnFrameRcvd (
    321   IN EFI_EVENT  Event,
    322   IN VOID       *Context
    323   )
    324 {
    325   //
    326   // Request ArpOnFrameRcvdDpc as a DPC at TPL_CALLBACK
    327   //
    328   QueueDpc (TPL_CALLBACK, ArpOnFrameRcvdDpc, Context);
    329 }
    330 
    331 /**
    332   Process the already sent arp packets.
    333 
    334   @param[in]  Context                Pointer to the context data registerd to the
    335                                      Event.
    336 
    337   @return None.
    338 
    339 **/
    340 VOID
    341 EFIAPI
    342 ArpOnFrameSentDpc (
    343   IN VOID       *Context
    344   )
    345 {
    346   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;
    347   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;
    348 
    349   ASSERT (Context != NULL);
    350 
    351   TxToken = (EFI_MANAGED_NETWORK_COMPLETION_TOKEN *)Context;
    352   TxData  = TxToken->Packet.TxData;
    353 
    354   DEBUG_CODE (
    355     if (EFI_ERROR (TxToken->Status)) {
    356       DEBUG ((EFI_D_ERROR, "ArpOnFrameSent: TxToken->Status, %r.\n", TxToken->Status));
    357     }
    358   );
    359 
    360   //
    361   // Free the allocated memory and close the event.
    362   //
    363   FreePool (TxData->FragmentTable[0].FragmentBuffer);
    364   FreePool (TxData);
    365   gBS->CloseEvent (TxToken->Event);
    366   FreePool (TxToken);
    367 }
    368 
    369 /**
    370   Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK.
    371 
    372   @param[in]  Event                  The Event this notify function registered to.
    373   @param[in]  Context                Pointer to the context data registerd to the
    374                                      Event.
    375 
    376   @return None.
    377 
    378 **/
    379 VOID
    380 EFIAPI
    381 ArpOnFrameSent (
    382   IN EFI_EVENT  Event,
    383   IN VOID       *Context
    384   )
    385 {
    386   //
    387   // Request ArpOnFrameSentDpc as a DPC at TPL_CALLBACK
    388   //
    389   QueueDpc (TPL_CALLBACK, ArpOnFrameSentDpc, Context);
    390 }
    391 
    392 
    393 /**
    394   Process the arp cache olding and drive the retrying arp requests.
    395 
    396   @param[in]  Event                  The Event this notify function registered to.
    397   @param[in]  Context                Pointer to the context data registerd to the
    398                                      Event.
    399 
    400   @return None.
    401 
    402 **/
    403 VOID
    404 EFIAPI
    405 ArpTimerHandler (
    406   IN EFI_EVENT  Event,
    407   IN VOID       *Context
    408   )
    409 {
    410   ARP_SERVICE_DATA      *ArpService;
    411   LIST_ENTRY            *Entry;
    412   LIST_ENTRY            *NextEntry;
    413   LIST_ENTRY            *ContextEntry;
    414   ARP_CACHE_ENTRY       *CacheEntry;
    415   USER_REQUEST_CONTEXT  *RequestContext;
    416 
    417   ASSERT (Context != NULL);
    418   ArpService = (ARP_SERVICE_DATA *)Context;
    419 
    420   //
    421   // Iterate all the pending requests to see whether a retry is needed to send out
    422   // or the request finally fails because the retry time reaches the limitation.
    423   //
    424   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
    425     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
    426 
    427     if (CacheEntry->NextRetryTime <= ARP_PERIODIC_TIMER_INTERVAL) {
    428       //
    429       // Timeout, if we can retry more, send out the request again, otherwise abort
    430       // this request.
    431       //
    432       if (CacheEntry->RetryCount == 0) {
    433         //
    434         // Abort this request.
    435         //
    436         ArpAddressResolved (CacheEntry, NULL, NULL);
    437         ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
    438 
    439         RemoveEntryList (&CacheEntry->List);
    440         FreePool (CacheEntry);
    441       } else {
    442         //
    443         // resend the ARP request.
    444         //
    445         ASSERT (!IsListEmpty(&CacheEntry->UserRequestList));
    446 
    447         ContextEntry   = CacheEntry->UserRequestList.ForwardLink;
    448         RequestContext = NET_LIST_USER_STRUCT (ContextEntry, USER_REQUEST_CONTEXT, List);
    449 
    450         ArpSendFrame (RequestContext->Instance, CacheEntry, ARP_OPCODE_REQUEST);
    451 
    452         CacheEntry->RetryCount--;
    453         CacheEntry->NextRetryTime = RequestContext->Instance->ConfigData.RetryTimeOut;
    454       }
    455     } else {
    456       //
    457       // Update the NextRetryTime.
    458       //
    459       CacheEntry->NextRetryTime -= ARP_PERIODIC_TIMER_INTERVAL;
    460     }
    461   }
    462 
    463   //
    464   // Check the timeouts for the DeniedCacheTable.
    465   //
    466   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->DeniedCacheTable) {
    467     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
    468     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
    469 
    470     if (CacheEntry->DefaultDecayTime == 0) {
    471       //
    472       // It's a static entry, skip it.
    473       //
    474       continue;
    475     }
    476 
    477     if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
    478       //
    479       // Time out, remove it.
    480       //
    481       RemoveEntryList (&CacheEntry->List);
    482       FreePool (CacheEntry);
    483     } else {
    484       //
    485       // Update the DecayTime.
    486       //
    487       CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
    488     }
    489   }
    490 
    491   //
    492   // Check the timeouts for the ResolvedCacheTable.
    493   //
    494   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->ResolvedCacheTable) {
    495     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
    496     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
    497 
    498     if (CacheEntry->DefaultDecayTime == 0) {
    499       //
    500       // It's a static entry, skip it.
    501       //
    502       continue;
    503     }
    504 
    505     if (CacheEntry->DecayTime <= ARP_PERIODIC_TIMER_INTERVAL) {
    506       //
    507       // Time out, remove it.
    508       //
    509       RemoveEntryList (&CacheEntry->List);
    510       FreePool (CacheEntry);
    511     } else {
    512       //
    513       // Update the DecayTime.
    514       //
    515       CacheEntry->DecayTime -= ARP_PERIODIC_TIMER_INTERVAL;
    516     }
    517   }
    518 }
    519 
    520 
    521 /**
    522   Match the two NET_ARP_ADDRESSes.
    523 
    524   @param[in]  AddressOne             Pointer to the first address to match.
    525   @param[in]  AddressTwo             Pointer to the second address to match.
    526 
    527   @return The two addresses match or not.
    528 
    529 **/
    530 BOOLEAN
    531 ArpMatchAddress (
    532   IN NET_ARP_ADDRESS  *AddressOne,
    533   IN NET_ARP_ADDRESS  *AddressTwo
    534   )
    535 {
    536   ASSERT (AddressOne != NULL && AddressTwo != NULL);
    537 
    538   if ((AddressOne->Type != AddressTwo->Type) ||
    539     (AddressOne->Length != AddressTwo->Length)) {
    540     //
    541     // Either Type or Length doesn't match.
    542     //
    543     return FALSE;
    544   }
    545 
    546   if ((AddressOne->AddressPtr != NULL) &&
    547     (CompareMem (
    548       AddressOne->AddressPtr,
    549       AddressTwo->AddressPtr,
    550       AddressOne->Length
    551       ) != 0)) {
    552     //
    553     // The address is not the same.
    554     //
    555     return FALSE;
    556   }
    557 
    558   return TRUE;
    559 }
    560 
    561 
    562 /**
    563   Find the CacheEntry which matches the requirements in the specified CacheTable.
    564 
    565   @param[in]  CacheTable             Pointer to the arp cache table.
    566   @param[in]  StartEntry             Pointer to the start entry this search begins with
    567                                      in the cache table.
    568   @param[in]  FindOpType             The search type.
    569   @param[in]  ProtocolAddress        Pointer to the protocol address to match.
    570   @param[in]  HardwareAddress        Pointer to the hardware address to match.
    571 
    572   @return Pointer to the matched arp cache entry, if NULL, no match is found.
    573 
    574 **/
    575 ARP_CACHE_ENTRY *
    576 ArpFindNextCacheEntryInTable (
    577   IN LIST_ENTRY        *CacheTable,
    578   IN LIST_ENTRY        *StartEntry,
    579   IN FIND_OPTYPE       FindOpType,
    580   IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
    581   IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
    582   )
    583 {
    584   LIST_ENTRY       *Entry;
    585   ARP_CACHE_ENTRY  *CacheEntry;
    586 
    587   if (StartEntry == NULL) {
    588     //
    589     // Start from the beginning of the table if no StartEntry is specified.
    590     //
    591     StartEntry = CacheTable;
    592   }
    593 
    594   for (Entry = StartEntry->ForwardLink; Entry != CacheTable; Entry = Entry->ForwardLink) {
    595     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
    596 
    597     if ((FindOpType & MATCH_SW_ADDRESS) != 0) {
    598       //
    599       // Find by the software address.
    600       //
    601       if (!ArpMatchAddress (ProtocolAddress, &CacheEntry->Addresses[Protocol])) {
    602         //
    603         // The ProtocolAddress doesn't match, continue to the next cache entry.
    604         //
    605         continue;
    606       }
    607     }
    608 
    609     if ((FindOpType & MATCH_HW_ADDRESS) != 0) {
    610       //
    611       // Find by the hardware address.
    612       //
    613       if (!ArpMatchAddress (HardwareAddress, &CacheEntry->Addresses[Hardware])) {
    614         //
    615         // The HardwareAddress doesn't match, continue to the next cache entry.
    616         //
    617         continue;
    618       }
    619     }
    620 
    621     //
    622     // The CacheEntry meets the requirements now, return this entry.
    623     //
    624     return CacheEntry;
    625   }
    626 
    627   //
    628   // No matching.
    629   //
    630   return NULL;
    631 }
    632 
    633 
    634 /**
    635   Find the CacheEntry, using ProtocolAddress or HardwareAddress or both, as the keyword,
    636   in the DeniedCacheTable.
    637 
    638   @param[in]  ArpService             Pointer to the arp service context data.
    639   @param[in]  ProtocolAddress        Pointer to the protocol address.
    640   @param[in]  HardwareAddress        Pointer to the hardware address.
    641 
    642   @return Pointer to the matched cache entry, if NULL no match is found.
    643 
    644 **/
    645 ARP_CACHE_ENTRY *
    646 ArpFindDeniedCacheEntry (
    647   IN ARP_SERVICE_DATA  *ArpService,
    648   IN NET_ARP_ADDRESS   *ProtocolAddress OPTIONAL,
    649   IN NET_ARP_ADDRESS   *HardwareAddress OPTIONAL
    650   )
    651 {
    652   ARP_CACHE_ENTRY  *CacheEntry;
    653 
    654   ASSERT ((ProtocolAddress != NULL) || (HardwareAddress != NULL));
    655   NET_CHECK_SIGNATURE (ArpService, ARP_SERVICE_DATA_SIGNATURE);
    656 
    657   CacheEntry = NULL;
    658 
    659   if ((ProtocolAddress != NULL) && (ProtocolAddress->AddressPtr != NULL)) {
    660     //
    661     // Find the cache entry in the DeniedCacheTable by the protocol address.
    662     //
    663     CacheEntry = ArpFindNextCacheEntryInTable (
    664                    &ArpService->DeniedCacheTable,
    665                    NULL,
    666                    ByProtoAddress,
    667                    ProtocolAddress,
    668                    NULL
    669                    );
    670     if (CacheEntry != NULL) {
    671       //
    672       // There is a match.
    673       //
    674       return CacheEntry;
    675     }
    676   }
    677 
    678   if ((HardwareAddress != NULL) && (HardwareAddress->AddressPtr != NULL)) {
    679     //
    680     // Find the cache entry in the DeniedCacheTable by the hardware address.
    681     //
    682     CacheEntry = ArpFindNextCacheEntryInTable (
    683                    &ArpService->DeniedCacheTable,
    684                    NULL,
    685                    ByHwAddress,
    686                    NULL,
    687                    HardwareAddress
    688                    );
    689   }
    690 
    691   return CacheEntry;
    692 }
    693 
    694 
    695 /**
    696   Allocate a cache entry and initialize it.
    697 
    698   @param[in]  Instance               Pointer to the instance context data.
    699 
    700   @return Pointer to the new created cache entry.
    701 
    702 **/
    703 ARP_CACHE_ENTRY *
    704 ArpAllocCacheEntry (
    705   IN ARP_INSTANCE_DATA  *Instance
    706   )
    707 {
    708   ARP_CACHE_ENTRY  *CacheEntry;
    709   NET_ARP_ADDRESS  *Address;
    710   UINT16           Index;
    711 
    712   //
    713   // Allocate memory for the cache entry.
    714   //
    715   CacheEntry = AllocatePool (sizeof (ARP_CACHE_ENTRY));
    716   if (CacheEntry == NULL) {
    717     return NULL;
    718   }
    719 
    720   //
    721   // Init the lists.
    722   //
    723   InitializeListHead (&CacheEntry->List);
    724   InitializeListHead (&CacheEntry->UserRequestList);
    725 
    726   for (Index = 0; Index < 2; Index++) {
    727     //
    728     // Init the address pointers to point to the concrete buffer.
    729     //
    730     Address = &CacheEntry->Addresses[Index];
    731     Address->AddressPtr = Address->Buffer.ProtoAddress;
    732   }
    733 
    734   //
    735   // Zero the hardware address first.
    736   //
    737   ZeroMem (CacheEntry->Addresses[Hardware].AddressPtr, ARP_MAX_HARDWARE_ADDRESS_LEN);
    738 
    739   if (Instance != NULL) {
    740     //
    741     // Inherit the parameters from the instance configuration.
    742     //
    743     CacheEntry->RetryCount       = Instance->ConfigData.RetryCount;
    744     CacheEntry->NextRetryTime    = Instance->ConfigData.RetryTimeOut;
    745     CacheEntry->DefaultDecayTime = Instance->ConfigData.EntryTimeOut;
    746     CacheEntry->DecayTime        = Instance->ConfigData.EntryTimeOut;
    747   } else {
    748     //
    749     // Use the default parameters if this cache entry isn't allocate in a
    750     // instance's  scope.
    751     //
    752     CacheEntry->RetryCount       = ARP_DEFAULT_RETRY_COUNT;
    753     CacheEntry->NextRetryTime    = ARP_DEFAULT_RETRY_INTERVAL;
    754     CacheEntry->DefaultDecayTime = ARP_DEFAULT_TIMEOUT_VALUE;
    755     CacheEntry->DecayTime        = ARP_DEFAULT_TIMEOUT_VALUE;
    756   }
    757 
    758   return CacheEntry;
    759 }
    760 
    761 
    762 /**
    763   Turn the CacheEntry into the resolved status.
    764 
    765   @param[in]  CacheEntry             Pointer to the resolved cache entry.
    766   @param[in]  Instance               Pointer to the instance context data.
    767   @param[in]  UserEvent              Pointer to the UserEvent to notify.
    768 
    769   @return The count of notifications sent to the instance.
    770 
    771 **/
    772 UINTN
    773 ArpAddressResolved (
    774   IN ARP_CACHE_ENTRY    *CacheEntry,
    775   IN ARP_INSTANCE_DATA  *Instance OPTIONAL,
    776   IN EFI_EVENT          UserEvent OPTIONAL
    777   )
    778 {
    779   LIST_ENTRY            *Entry;
    780   LIST_ENTRY            *NextEntry;
    781   USER_REQUEST_CONTEXT  *Context;
    782   UINTN                 Count;
    783 
    784   Count = 0;
    785 
    786   //
    787   // Iterate all the linked user requests to notify them.
    788   //
    789   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &CacheEntry->UserRequestList) {
    790     Context = NET_LIST_USER_STRUCT (Entry, USER_REQUEST_CONTEXT, List);
    791 
    792     if (((Instance == NULL) || (Context->Instance == Instance)) &&
    793       ((UserEvent == NULL) || (Context->UserRequestEvent == UserEvent))) {
    794       //
    795       // Copy the address to the user-provided buffer and notify the user.
    796       //
    797       CopyMem (
    798         Context->UserHwAddrBuffer,
    799         CacheEntry->Addresses[Hardware].AddressPtr,
    800         CacheEntry->Addresses[Hardware].Length
    801         );
    802       gBS->SignalEvent (Context->UserRequestEvent);
    803 
    804       //
    805       // Remove this user request and free the context data.
    806       //
    807       RemoveEntryList (&Context->List);
    808       FreePool (Context);
    809 
    810       Count++;
    811     }
    812   }
    813 
    814   //
    815   // Dispatch the DPCs queued by the NotifyFunction of the Context->UserRequestEvent.
    816   //
    817   DispatchDpc ();
    818 
    819   return Count;
    820 }
    821 
    822 
    823 /**
    824   Fill the addresses in the CacheEntry using the information passed in by
    825   HwAddr and SwAddr.
    826 
    827   @param[in]  CacheEntry             Pointer to the cache entry.
    828   @param[in]  HwAddr                 Pointer to the software address.
    829   @param[in]  SwAddr                 Pointer to the hardware address.
    830 
    831   @return None.
    832 
    833 **/
    834 VOID
    835 ArpFillAddressInCacheEntry (
    836   IN ARP_CACHE_ENTRY  *CacheEntry,
    837   IN NET_ARP_ADDRESS  *HwAddr OPTIONAL,
    838   IN NET_ARP_ADDRESS  *SwAddr OPTIONAL
    839   )
    840 {
    841   NET_ARP_ADDRESS  *Address[2];
    842   NET_ARP_ADDRESS  *CacheAddress;
    843   UINT32           Index;
    844 
    845   Address[Hardware] = HwAddr;
    846   Address[Protocol] = SwAddr;
    847 
    848   for (Index = 0; Index < 2; Index++) {
    849     if (Address[Index] != NULL) {
    850       //
    851       // Fill the address if the passed in pointer is not NULL.
    852       //
    853       CacheAddress = &CacheEntry->Addresses[Index];
    854 
    855       CacheAddress->Type   = Address[Index]->Type;
    856       CacheAddress->Length = Address[Index]->Length;
    857 
    858       if (Address[Index]->AddressPtr != NULL) {
    859         //
    860         // Copy it if the AddressPtr points to some buffer.
    861         //
    862         CopyMem (
    863           CacheAddress->AddressPtr,
    864           Address[Index]->AddressPtr,
    865           CacheAddress->Length
    866           );
    867       } else {
    868         //
    869         // Zero the corresponding address buffer in the CacheEntry.
    870         //
    871         ZeroMem (CacheAddress->AddressPtr, CacheAddress->Length);
    872       }
    873     }
    874   }
    875 }
    876 
    877 
    878 /**
    879   Configure the instance using the ConfigData. ConfigData is already validated.
    880 
    881   @param[in]  Instance           Pointer to the instance context data to be
    882                                  configured.
    883   @param[in]  ConfigData         Pointer to the configuration data used to
    884                                  configure the instance.
    885 
    886   @retval EFI_SUCCESS            The instance is configured with the ConfigData.
    887   @retval EFI_ACCESS_DENIED      The instance is already configured and the
    888                                  ConfigData tries to reset some unchangeable
    889                                  fields.
    890   @retval EFI_INVALID_PARAMETER  The ConfigData provides a non-unicast IPv4 address
    891                                  when the SwAddressType is IPv4.
    892   @retval EFI_OUT_OF_RESOURCES   The instance fails to configure due to memory
    893                                  limitation.
    894 
    895 **/
    896 EFI_STATUS
    897 ArpConfigureInstance (
    898   IN ARP_INSTANCE_DATA    *Instance,
    899   IN EFI_ARP_CONFIG_DATA  *ConfigData OPTIONAL
    900   )
    901 {
    902   EFI_ARP_CONFIG_DATA  *OldConfigData;
    903   IP4_ADDR             Ip;
    904 
    905   OldConfigData = &Instance->ConfigData;
    906 
    907   if (ConfigData != NULL) {
    908 
    909     if (Instance->Configured) {
    910       //
    911       // The instance is configured, check the unchangeable fields.
    912       //
    913       if ((OldConfigData->SwAddressType != ConfigData->SwAddressType) ||
    914         (OldConfigData->SwAddressLength != ConfigData->SwAddressLength) ||
    915         (CompareMem (
    916            OldConfigData->StationAddress,
    917            ConfigData->StationAddress,
    918            OldConfigData->SwAddressLength
    919            ) != 0)) {
    920         //
    921         // Deny the unallowed changes.
    922         //
    923         return EFI_ACCESS_DENIED;
    924       }
    925     } else {
    926       //
    927       // The instance is not configured.
    928       //
    929 
    930       if (ConfigData->SwAddressType == IPV4_ETHER_PROTO_TYPE) {
    931         CopyMem (&Ip, ConfigData->StationAddress, sizeof (IP4_ADDR));
    932 
    933         if (!NetIp4IsUnicast (NTOHL (Ip), 0)) {
    934           //
    935           // The station address is not a valid IPv4 unicast address.
    936           //
    937           return EFI_INVALID_PARAMETER;
    938         }
    939       }
    940 
    941       //
    942       // Save the configuration.
    943       //
    944       CopyMem (OldConfigData, ConfigData, sizeof (*OldConfigData));
    945 
    946       OldConfigData->StationAddress = AllocatePool (OldConfigData->SwAddressLength);
    947       if (OldConfigData->StationAddress == NULL) {
    948         DEBUG ((EFI_D_ERROR, "ArpConfigInstance: AllocatePool for the StationAddress "
    949           "failed.\n"));
    950         return EFI_OUT_OF_RESOURCES;
    951       }
    952 
    953       //
    954       // Save the StationAddress.
    955       //
    956       CopyMem (
    957         OldConfigData->StationAddress,
    958         ConfigData->StationAddress,
    959         OldConfigData->SwAddressLength
    960         );
    961 
    962       //
    963       // Set the state to configured.
    964       //
    965       Instance->Configured = TRUE;
    966     }
    967 
    968     //
    969     // Use the implementation specific values if the following field is zero.
    970     //
    971     OldConfigData->EntryTimeOut = (ConfigData->EntryTimeOut == 0) ?
    972       ARP_DEFAULT_TIMEOUT_VALUE : ConfigData->EntryTimeOut;
    973 
    974     OldConfigData->RetryCount   = (ConfigData->RetryCount == 0) ?
    975       ARP_DEFAULT_RETRY_COUNT : ConfigData->RetryCount;
    976 
    977     OldConfigData->RetryTimeOut = (ConfigData->RetryTimeOut == 0) ?
    978       ARP_DEFAULT_RETRY_INTERVAL : ConfigData->RetryTimeOut;
    979   } else {
    980     //
    981     // Reset the configuration.
    982     //
    983 
    984     if (Instance->Configured) {
    985       //
    986       // Cancel the arp requests issued by this instance.
    987       //
    988       Instance->ArpProto.Cancel (&Instance->ArpProto, NULL, NULL);
    989 
    990       //
    991       // Free the buffer previously allocated to hold the station address.
    992       //
    993       FreePool (OldConfigData->StationAddress);
    994     }
    995 
    996     Instance->Configured = FALSE;
    997   }
    998 
    999   return EFI_SUCCESS;
   1000 }
   1001 
   1002 
   1003 /**
   1004   Send out an arp frame using the CachEntry and the ArpOpCode.
   1005 
   1006   @param[in]  Instance               Pointer to the instance context data.
   1007   @param[in]  CacheEntry             Pointer to the configuration data used to
   1008                                      configure the instance.
   1009   @param[in]  ArpOpCode              The opcode used to send out this Arp frame, either
   1010                                      request or reply.
   1011 
   1012   @return None.
   1013 
   1014 **/
   1015 VOID
   1016 ArpSendFrame (
   1017   IN ARP_INSTANCE_DATA  *Instance,
   1018   IN ARP_CACHE_ENTRY    *CacheEntry,
   1019   IN UINT16             ArpOpCode
   1020   )
   1021 {
   1022   EFI_STATUS                            Status;
   1023   EFI_MANAGED_NETWORK_COMPLETION_TOKEN  *TxToken;
   1024   EFI_MANAGED_NETWORK_TRANSMIT_DATA     *TxData;
   1025   UINT32                                TotalLength;
   1026   UINT8                                 *Packet;
   1027   ARP_SERVICE_DATA                      *ArpService;
   1028   EFI_SIMPLE_NETWORK_MODE               *SnpMode;
   1029   EFI_ARP_CONFIG_DATA                   *ConfigData;
   1030   UINT8                                 *TmpPtr;
   1031   ARP_HEAD                              *ArpHead;
   1032 
   1033   ASSERT ((Instance != NULL) && (CacheEntry != NULL));
   1034 
   1035   //
   1036   // Allocate memory for the TxToken.
   1037   //
   1038   TxToken = AllocatePool (sizeof(EFI_MANAGED_NETWORK_COMPLETION_TOKEN));
   1039   if (TxToken == NULL) {
   1040     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxToken failed.\n"));
   1041     return;
   1042   }
   1043 
   1044   TxToken->Event = NULL;
   1045   TxData         = NULL;
   1046   Packet         = NULL;
   1047 
   1048   //
   1049   // Create the event for this TxToken.
   1050   //
   1051   Status = gBS->CreateEvent (
   1052                   EVT_NOTIFY_SIGNAL,
   1053                   TPL_NOTIFY,
   1054                   ArpOnFrameSent,
   1055                   (VOID *)TxToken,
   1056                   &TxToken->Event
   1057                   );
   1058   if (EFI_ERROR (Status)) {
   1059     DEBUG ((EFI_D_ERROR, "ArpSendFrame: CreateEvent failed for TxToken->Event.\n"));
   1060     goto CLEAN_EXIT;
   1061   }
   1062 
   1063   //
   1064   // Allocate memory for the TxData used in the TxToken.
   1065   //
   1066   TxData = AllocatePool (sizeof(EFI_MANAGED_NETWORK_TRANSMIT_DATA));
   1067   if (TxData == NULL) {
   1068     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for TxData failed.\n"));
   1069     goto CLEAN_EXIT;
   1070   }
   1071 
   1072   ArpService = Instance->ArpService;
   1073   SnpMode    = &ArpService->SnpMode;
   1074   ConfigData = &Instance->ConfigData;
   1075 
   1076   //
   1077   // Calculate the buffer length for this arp frame.
   1078   //
   1079   TotalLength = SnpMode->MediaHeaderSize + sizeof (ARP_HEAD) +
   1080                 2 * (ConfigData->SwAddressLength + SnpMode->HwAddressSize);
   1081 
   1082   //
   1083   // Allocate buffer for the arp frame.
   1084   //
   1085   Packet = AllocatePool (TotalLength);
   1086   if (Packet == NULL) {
   1087     DEBUG ((EFI_D_ERROR, "ArpSendFrame: Allocate memory for Packet failed.\n"));
   1088     ASSERT (Packet != NULL);
   1089   }
   1090 
   1091   TmpPtr = Packet;
   1092 
   1093   //
   1094   // The destination MAC address.
   1095   //
   1096   if (ArpOpCode == ARP_OPCODE_REQUEST) {
   1097     CopyMem (TmpPtr, &SnpMode->BroadcastAddress, SnpMode->HwAddressSize);
   1098   } else {
   1099     CopyMem (
   1100       TmpPtr,
   1101       CacheEntry->Addresses[Hardware].AddressPtr,
   1102       SnpMode->HwAddressSize
   1103       );
   1104   }
   1105   TmpPtr += SnpMode->HwAddressSize;
   1106 
   1107   //
   1108   // The source MAC address.
   1109   //
   1110   CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
   1111   TmpPtr += SnpMode->HwAddressSize;
   1112 
   1113   //
   1114   // The ethernet protocol type.
   1115   //
   1116   *(UINT16 *)TmpPtr = HTONS (ARP_ETHER_PROTO_TYPE);
   1117   TmpPtr            += 2;
   1118 
   1119   //
   1120   // The ARP Head.
   1121   //
   1122   ArpHead               = (ARP_HEAD *) TmpPtr;
   1123   ArpHead->HwType       = HTONS ((UINT16)SnpMode->IfType);
   1124   ArpHead->ProtoType    = HTONS (ConfigData->SwAddressType);
   1125   ArpHead->HwAddrLen    = (UINT8)SnpMode->HwAddressSize;
   1126   ArpHead->ProtoAddrLen = ConfigData->SwAddressLength;
   1127   ArpHead->OpCode       = HTONS (ArpOpCode);
   1128   TmpPtr                += sizeof (ARP_HEAD);
   1129 
   1130   //
   1131   // The sender hardware address.
   1132   //
   1133   CopyMem (TmpPtr, &SnpMode->CurrentAddress, SnpMode->HwAddressSize);
   1134   TmpPtr += SnpMode->HwAddressSize;
   1135 
   1136   //
   1137   // The sender protocol address.
   1138   //
   1139   CopyMem (TmpPtr, ConfigData->StationAddress, ConfigData->SwAddressLength);
   1140   TmpPtr += ConfigData->SwAddressLength;
   1141 
   1142   //
   1143   // The target hardware address.
   1144   //
   1145   CopyMem (
   1146     TmpPtr,
   1147     CacheEntry->Addresses[Hardware].AddressPtr,
   1148     SnpMode->HwAddressSize
   1149     );
   1150   TmpPtr += SnpMode->HwAddressSize;
   1151 
   1152   //
   1153   // The target protocol address.
   1154   //
   1155   CopyMem (
   1156     TmpPtr,
   1157     CacheEntry->Addresses[Protocol].AddressPtr,
   1158     ConfigData->SwAddressLength
   1159     );
   1160 
   1161   //
   1162   // Set all the fields of the TxData.
   1163   //
   1164   TxData->DestinationAddress = NULL;
   1165   TxData->SourceAddress      = NULL;
   1166   TxData->ProtocolType       = 0;
   1167   TxData->DataLength         = TotalLength - SnpMode->MediaHeaderSize;
   1168   TxData->HeaderLength       = (UINT16) SnpMode->MediaHeaderSize;
   1169   TxData->FragmentCount      = 1;
   1170 
   1171   TxData->FragmentTable[0].FragmentBuffer = Packet;
   1172   TxData->FragmentTable[0].FragmentLength = TotalLength;
   1173 
   1174   //
   1175   // Associate the TxData with the TxToken.
   1176   //
   1177   TxToken->Packet.TxData = TxData;
   1178   TxToken->Status        = EFI_NOT_READY;
   1179 
   1180   //
   1181   // Send out this arp packet by Mnp.
   1182   //
   1183   Status = ArpService->Mnp->Transmit (ArpService->Mnp, TxToken);
   1184   if (EFI_ERROR (Status)) {
   1185     DEBUG ((EFI_D_ERROR, "Mnp->Transmit failed, %r.\n", Status));
   1186     goto CLEAN_EXIT;
   1187   }
   1188 
   1189   return;
   1190 
   1191 CLEAN_EXIT:
   1192 
   1193   if (Packet != NULL) {
   1194     FreePool (Packet);
   1195   }
   1196 
   1197   if (TxData != NULL) {
   1198     FreePool (TxData);
   1199   }
   1200 
   1201   if (TxToken->Event != NULL) {
   1202     gBS->CloseEvent (TxToken->Event);
   1203   }
   1204 
   1205   FreePool (TxToken);
   1206 }
   1207 
   1208 
   1209 /**
   1210   Delete the cache entries in the specified CacheTable, using the BySwAddress,
   1211   SwAddressType, AddressBuffer combination as the matching key, if Force is TRUE,
   1212   the cache is deleted event it's a static entry.
   1213 
   1214   @param[in]  CacheTable             Pointer to the cache table to do the deletion.
   1215   @param[in]  BySwAddress            Delete the cache entry by software address or by
   1216                                      hardware address.
   1217   @param[in]  SwAddressType          The software address used to do the deletion.
   1218   @param[in]  AddressBuffer          Pointer to the buffer containing the address to
   1219                                      match for the deletion.
   1220   @param[in]  Force                  This deletion is forced or not.
   1221 
   1222   @return The count of the deleted cache entries.
   1223 
   1224 **/
   1225 UINTN
   1226 ArpDeleteCacheEntryInTable (
   1227   IN LIST_ENTRY      *CacheTable,
   1228   IN BOOLEAN         BySwAddress,
   1229   IN UINT16          SwAddressType,
   1230   IN UINT8           *AddressBuffer OPTIONAL,
   1231   IN BOOLEAN         Force
   1232   )
   1233 {
   1234   LIST_ENTRY       *Entry;
   1235   LIST_ENTRY       *NextEntry;
   1236   ARP_CACHE_ENTRY  *CacheEntry;
   1237   UINTN            Count;
   1238 
   1239   Count = 0;
   1240 
   1241   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, CacheTable) {
   1242     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
   1243 
   1244     if ((CacheEntry->DefaultDecayTime == 0) && !Force) {
   1245       //
   1246       // It's a static entry and we are not forced to delete it, skip.
   1247       //
   1248       continue;
   1249     }
   1250 
   1251     if (BySwAddress) {
   1252       if (SwAddressType == CacheEntry->Addresses[Protocol].Type) {
   1253         //
   1254         // Protocol address type matched. Check the address.
   1255         //
   1256         if ((AddressBuffer == NULL) ||
   1257           (CompareMem (
   1258              AddressBuffer,
   1259              CacheEntry->Addresses[Protocol].AddressPtr,
   1260              CacheEntry->Addresses[Protocol].Length
   1261              ) == 0)) {
   1262           //
   1263           // Address matched.
   1264           //
   1265           goto MATCHED;
   1266         }
   1267       }
   1268     } else {
   1269       if ((AddressBuffer == NULL) ||
   1270         (CompareMem (
   1271            AddressBuffer,
   1272            CacheEntry->Addresses[Hardware].AddressPtr,
   1273            CacheEntry->Addresses[Hardware].Length
   1274            ) == 0)) {
   1275         //
   1276         // Address matched.
   1277         //
   1278         goto MATCHED;
   1279       }
   1280     }
   1281 
   1282     continue;
   1283 
   1284 MATCHED:
   1285 
   1286     //
   1287     // Delete this entry.
   1288     //
   1289     RemoveEntryList (&CacheEntry->List);
   1290     ASSERT (IsListEmpty (&CacheEntry->UserRequestList));
   1291     FreePool (CacheEntry);
   1292 
   1293     Count++;
   1294   }
   1295 
   1296   return Count;
   1297 }
   1298 
   1299 
   1300 /**
   1301   Delete cache entries in all the cache tables.
   1302 
   1303   @param[in]  Instance               Pointer to the instance context data.
   1304   @param[in]  BySwAddress            Delete the cache entry by software address or by
   1305                                      hardware address.
   1306   @param[in]  AddressBuffer          Pointer to the buffer containing the address to
   1307                                      match for the deletion.
   1308   @param[in]  Force                  This deletion is forced or not.
   1309 
   1310   @return The count of the deleted cache entries.
   1311 
   1312 **/
   1313 UINTN
   1314 ArpDeleteCacheEntry (
   1315   IN ARP_INSTANCE_DATA  *Instance,
   1316   IN BOOLEAN            BySwAddress,
   1317   IN UINT8              *AddressBuffer OPTIONAL,
   1318   IN BOOLEAN            Force
   1319   )
   1320 {
   1321   ARP_SERVICE_DATA  *ArpService;
   1322   UINTN             Count;
   1323 
   1324   NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
   1325 
   1326   ArpService = Instance->ArpService;
   1327 
   1328   //
   1329   // Delete the cache entries in the DeniedCacheTable.
   1330   //
   1331   Count = ArpDeleteCacheEntryInTable (
   1332             &ArpService->DeniedCacheTable,
   1333             BySwAddress,
   1334             Instance->ConfigData.SwAddressType,
   1335             AddressBuffer,
   1336             Force
   1337             );
   1338 
   1339   //
   1340   // Delete the cache entries inthe ResolvedCacheTable.
   1341   //
   1342   Count += ArpDeleteCacheEntryInTable (
   1343              &ArpService->ResolvedCacheTable,
   1344              BySwAddress,
   1345              Instance->ConfigData.SwAddressType,
   1346              AddressBuffer,
   1347              Force
   1348              );
   1349 
   1350   return Count;
   1351 }
   1352 
   1353 
   1354 /**
   1355   Cancel the arp request.
   1356 
   1357   @param[in]  Instance               Pointer to the instance context data.
   1358   @param[in]  TargetSwAddress        Pointer to the buffer containing the target
   1359                                      software address to match the arp request.
   1360   @param[in]  UserEvent              The user event used to notify this request
   1361                                      cancellation.
   1362 
   1363   @return The count of the cancelled requests.
   1364 
   1365 **/
   1366 UINTN
   1367 ArpCancelRequest (
   1368   IN ARP_INSTANCE_DATA  *Instance,
   1369   IN VOID               *TargetSwAddress OPTIONAL,
   1370   IN EFI_EVENT          UserEvent        OPTIONAL
   1371   )
   1372 {
   1373   ARP_SERVICE_DATA  *ArpService;
   1374   LIST_ENTRY        *Entry;
   1375   LIST_ENTRY        *NextEntry;
   1376   ARP_CACHE_ENTRY   *CacheEntry;
   1377   UINTN             Count;
   1378 
   1379   NET_CHECK_SIGNATURE (Instance, ARP_INSTANCE_DATA_SIGNATURE);
   1380 
   1381   ArpService = Instance->ArpService;
   1382 
   1383   Count = 0;
   1384   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &ArpService->PendingRequestTable) {
   1385     CacheEntry = NET_LIST_USER_STRUCT (Entry, ARP_CACHE_ENTRY, List);
   1386 
   1387     if ((TargetSwAddress == NULL) ||
   1388       (CompareMem (
   1389          TargetSwAddress,
   1390          CacheEntry->Addresses[Protocol].AddressPtr,
   1391          CacheEntry->Addresses[Protocol].Length
   1392          ) == 0)) {
   1393       //
   1394       // This request entry matches the TargetSwAddress or all requests are to be
   1395       // cancelled as TargetSwAddress is NULL.
   1396       //
   1397       Count += ArpAddressResolved (CacheEntry, Instance, UserEvent);
   1398 
   1399       if (IsListEmpty (&CacheEntry->UserRequestList)) {
   1400         //
   1401         // No user requests any more, remove this request cache entry.
   1402         //
   1403         RemoveEntryList (&CacheEntry->List);
   1404         FreePool (CacheEntry);
   1405       }
   1406     }
   1407   }
   1408 
   1409   return Count;
   1410 }
   1411 
   1412 
   1413 /**
   1414   Find the cache entry in the cache table.
   1415 
   1416   @param[in]  Instance           Pointer to the instance context data.
   1417   @param[in]  BySwAddress        Set to TRUE to look for matching software protocol
   1418                                  addresses. Set to FALSE to look for matching
   1419                                  hardware protocol addresses.
   1420   @param[in]  AddressBuffer      Pointer to address buffer. Set to NULL to match
   1421                                  all addresses.
   1422   @param[out] EntryLength        The size of an entry in the entries buffer.
   1423   @param[out] EntryCount         The number of ARP cache entries that are found by
   1424                                  the specified criteria.
   1425   @param[out] Entries            Pointer to the buffer that will receive the ARP
   1426                                  cache entries.
   1427   @param[in]  Refresh            Set to TRUE to refresh the timeout value of the
   1428                                  matching ARP cache entry.
   1429 
   1430   @retval EFI_SUCCESS            The requested ARP cache entries are copied into
   1431                                  the buffer.
   1432   @retval EFI_NOT_FOUND          No matching entries found.
   1433   @retval EFI_OUT_OF_RESOURCE    There is a memory allocation failure.
   1434 
   1435 **/
   1436 EFI_STATUS
   1437 ArpFindCacheEntry (
   1438   IN ARP_INSTANCE_DATA   *Instance,
   1439   IN BOOLEAN             BySwAddress,
   1440   IN VOID                *AddressBuffer OPTIONAL,
   1441   OUT UINT32             *EntryLength   OPTIONAL,
   1442   OUT UINT32             *EntryCount    OPTIONAL,
   1443   OUT EFI_ARP_FIND_DATA  **Entries      OPTIONAL,
   1444   IN BOOLEAN             Refresh
   1445   )
   1446 {
   1447   EFI_STATUS         Status;
   1448   ARP_SERVICE_DATA   *ArpService;
   1449   NET_ARP_ADDRESS    MatchAddress;
   1450   FIND_OPTYPE        FindOpType;
   1451   LIST_ENTRY         *StartEntry;
   1452   ARP_CACHE_ENTRY    *CacheEntry;
   1453   NET_MAP            FoundEntries;
   1454   UINT32             FoundCount;
   1455   EFI_ARP_FIND_DATA  *FindData;
   1456   LIST_ENTRY         *CacheTable;
   1457   UINT32             FoundEntryLength;
   1458 
   1459   ArpService = Instance->ArpService;
   1460 
   1461   //
   1462   // Init the FounEntries used to hold the found cache entries.
   1463   //
   1464   NetMapInit (&FoundEntries);
   1465 
   1466   //
   1467   // Set the MatchAddress.
   1468   //
   1469   if (BySwAddress) {
   1470     MatchAddress.Type   = Instance->ConfigData.SwAddressType;
   1471     MatchAddress.Length = Instance->ConfigData.SwAddressLength;
   1472     FindOpType          = ByProtoAddress;
   1473   } else {
   1474     MatchAddress.Type   = ArpService->SnpMode.IfType;
   1475     MatchAddress.Length = (UINT8)ArpService->SnpMode.HwAddressSize;
   1476     FindOpType          = ByHwAddress;
   1477   }
   1478 
   1479   MatchAddress.AddressPtr = AddressBuffer;
   1480 
   1481   //
   1482   // Search the DeniedCacheTable
   1483   //
   1484   StartEntry = NULL;
   1485   while (TRUE) {
   1486     //
   1487     // Try to find the matched entries in the DeniedCacheTable.
   1488     //
   1489     CacheEntry = ArpFindNextCacheEntryInTable (
   1490                    &ArpService->DeniedCacheTable,
   1491                    StartEntry,
   1492                    FindOpType,
   1493                    &MatchAddress,
   1494                    &MatchAddress
   1495                    );
   1496     if (CacheEntry == NULL) {
   1497       //
   1498       // Once the CacheEntry is NULL, there are no more matches.
   1499       //
   1500       break;
   1501     }
   1502 
   1503     //
   1504     // Insert the found entry into the map.
   1505     //
   1506     NetMapInsertTail (
   1507       &FoundEntries,
   1508       (VOID *)CacheEntry,
   1509       (VOID *)&ArpService->DeniedCacheTable
   1510       );
   1511 
   1512     //
   1513     // Let the next search start from this cache entry.
   1514     //
   1515     StartEntry = &CacheEntry->List;
   1516 
   1517     if (Refresh) {
   1518       //
   1519       // Refresh the DecayTime if needed.
   1520       //
   1521       CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
   1522     }
   1523   }
   1524 
   1525   //
   1526   // Search the ResolvedCacheTable
   1527   //
   1528   StartEntry = NULL;
   1529   while (TRUE) {
   1530     CacheEntry = ArpFindNextCacheEntryInTable (
   1531                    &ArpService->ResolvedCacheTable,
   1532                    StartEntry,
   1533                    FindOpType,
   1534                    &MatchAddress,
   1535                    &MatchAddress
   1536                    );
   1537     if (CacheEntry == NULL) {
   1538       //
   1539       // Once the CacheEntry is NULL, there are no more matches.
   1540       //
   1541       break;
   1542     }
   1543 
   1544     //
   1545     // Insert the found entry into the map.
   1546     //
   1547     NetMapInsertTail (
   1548       &FoundEntries,
   1549       (VOID *)CacheEntry,
   1550       (VOID *)&ArpService->ResolvedCacheTable
   1551       );
   1552 
   1553     //
   1554     // Let the next search start from this cache entry.
   1555     //
   1556     StartEntry = &CacheEntry->List;
   1557 
   1558     if (Refresh) {
   1559       //
   1560       // Refresh the DecayTime if needed.
   1561       //
   1562       CacheEntry->DecayTime = CacheEntry->DefaultDecayTime;
   1563     }
   1564   }
   1565 
   1566   Status = EFI_SUCCESS;
   1567 
   1568   FoundCount = (UINT32) NetMapGetCount (&FoundEntries);
   1569   if (FoundCount == 0) {
   1570     Status = EFI_NOT_FOUND;
   1571     goto CLEAN_EXIT;
   1572   }
   1573 
   1574   //
   1575   // Found the entry length, make sure its 8 bytes alignment.
   1576   //
   1577   FoundEntryLength = (((sizeof (EFI_ARP_FIND_DATA) + Instance->ConfigData.SwAddressLength +
   1578                        ArpService->SnpMode.HwAddressSize) + 3) & ~(0x3));
   1579 
   1580   if (EntryLength != NULL) {
   1581     *EntryLength = FoundEntryLength;
   1582   }
   1583 
   1584   if (EntryCount != NULL) {
   1585     //
   1586     // Return the found entry count.
   1587     //
   1588     *EntryCount = FoundCount;
   1589   }
   1590 
   1591   if (Entries == NULL) {
   1592     goto CLEAN_EXIT;
   1593   }
   1594 
   1595   //
   1596   // Allocate buffer to copy the found entries.
   1597   //
   1598   FindData = AllocatePool (FoundCount * FoundEntryLength);
   1599   if (FindData == NULL) {
   1600     DEBUG ((EFI_D_ERROR, "ArpFindCacheEntry: Failed to allocate memory.\n"));
   1601     Status = EFI_OUT_OF_RESOURCES;
   1602     goto CLEAN_EXIT;
   1603   }
   1604 
   1605   //
   1606   // Return the address to the user.
   1607   //
   1608   *Entries = FindData;
   1609 
   1610   //
   1611   // Dump the entries.
   1612   //
   1613   while (!NetMapIsEmpty (&FoundEntries)) {
   1614     //
   1615     // Get a cache entry from the map.
   1616     //
   1617     CacheEntry = NetMapRemoveHead (&FoundEntries, (VOID **)&CacheTable);
   1618 
   1619     //
   1620     // Set the fields in FindData.
   1621     //
   1622     FindData->Size            = FoundEntryLength;
   1623     FindData->DenyFlag        = (BOOLEAN)(CacheTable == &ArpService->DeniedCacheTable);
   1624     FindData->StaticFlag      = (BOOLEAN)(CacheEntry->DefaultDecayTime == 0);
   1625     FindData->HwAddressType   = ArpService->SnpMode.IfType;
   1626     FindData->SwAddressType   = Instance->ConfigData.SwAddressType;
   1627     FindData->HwAddressLength = (UINT8)ArpService->SnpMode.HwAddressSize;
   1628     FindData->SwAddressLength = Instance->ConfigData.SwAddressLength;
   1629 
   1630     //
   1631     // Copy the software address.
   1632     //
   1633     CopyMem (
   1634       FindData + 1,
   1635       CacheEntry->Addresses[Protocol].AddressPtr,
   1636       FindData->SwAddressLength
   1637       );
   1638 
   1639     //
   1640     // Copy the hardware address.
   1641     //
   1642     CopyMem (
   1643       (UINT8 *)(FindData + 1) + FindData->SwAddressLength,
   1644       CacheEntry->Addresses[Hardware].AddressPtr,
   1645       FindData->HwAddressLength
   1646       );
   1647 
   1648     //
   1649     // Slip to the next FindData.
   1650     //
   1651     FindData = (EFI_ARP_FIND_DATA *)((UINT8 *)FindData + FoundEntryLength);
   1652   }
   1653 
   1654 CLEAN_EXIT:
   1655 
   1656   NetMapClean (&FoundEntries);
   1657 
   1658   return Status;
   1659 }
   1660 
   1661