+/**\r
+ Get and record the arp cache\r
+\r
+ @param This Pointer to EFI_PXE_BC_PROTOCOL\r
+\r
+ @retval EFI_SUCCESS Arp cache updated successfully\r
+ @retval others If error occurs when updating arp cache\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+UpdateArpCache (\r
+ IN EFI_PXE_BASE_CODE_PROTOCOL * This\r
+ )\r
+{\r
+ PXEBC_PRIVATE_DATA *Private;\r
+ EFI_PXE_BASE_CODE_MODE *Mode;\r
+ EFI_STATUS Status;\r
+ UINT32 EntryLength;\r
+ UINT32 EntryCount;\r
+ EFI_ARP_FIND_DATA *Entries;\r
+ UINT32 Index;\r
+\r
+ Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
+ Mode = Private->PxeBc.Mode;\r
+\r
+ Status = Private->Arp->Find (Private->Arp, TRUE, NULL, &EntryLength, &EntryCount, &Entries, TRUE);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Mode->ArpCacheEntries = MIN (EntryCount, EFI_PXE_BASE_CODE_MAX_ARP_ENTRIES);\r
+ for (Index = 0; Index < Mode->ArpCacheEntries; Index ++) {\r
+ CopyMem (&Mode->ArpCache[Index].IpAddr, Entries + 1, Entries->SwAddressLength);\r
+ CopyMem (&Mode->ArpCache[Index].MacAddr, (UINT8 *)(Entries + 1) + Entries->SwAddressLength, Entries->HwAddressLength);\r
+ //\r
+ // Slip to the next FindData.\r
+ //\r
+ Entries = (EFI_ARP_FIND_DATA *)((UINT8 *)Entries + EntryLength);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Timeout routine to catch arp cache.\r
+\r
+ @param Event Pointer to EFI_PXE_BC_PROTOCOL\r
+ @param Context Context of the timer event\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+ArpCacheUpdateTimeout (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ UpdateArpCache ((EFI_PXE_BASE_CODE_PROTOCOL *) Context);\r
+}\r
+\r
+/**\r
+ Timeout routine to catch arp cache.\r
+\r
+ @param Event Pointer to EFI_PXE_BC_PROTOCOL\r
+ @param Context\r
+\r
+**/\r
+STATIC\r
+BOOLEAN\r
+FindInArpCache (\r
+ EFI_PXE_BASE_CODE_MODE *PxeBcMode,\r
+ EFI_IPv4_ADDRESS *Ip4Addr,\r
+ EFI_MAC_ADDRESS *MacAddress\r
+ )\r
+{\r
+ UINT32 Index;\r
+\r
+ for (Index = 0; Index < PxeBcMode->ArpCacheEntries; Index ++) {\r
+ if (EFI_IP4_EQUAL (&PxeBcMode->ArpCache[Index].IpAddr.v4, Ip4Addr)) {\r
+ CopyMem (MacAddress, &PxeBcMode->ArpCache[Index].MacAddr, sizeof (EFI_MAC_ADDRESS));\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Notify function for the ICMP receive token, used to process\r
+ the received ICMP packets.\r
+\r
+ @param Context The context passed in by the event notifier.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+IcmpErrorListenHandlerDpc (\r
+ IN VOID *Context\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_IP4_RECEIVE_DATA *RxData;\r
+ EFI_IP4_PROTOCOL *Ip4;\r
+ PXEBC_PRIVATE_DATA *Private;\r
+ EFI_PXE_BASE_CODE_MODE *Mode;\r
+ UINTN Index;\r
+ UINT32 CopiedLen;\r
+ UINT8 *CopiedPointer;\r
+\r
+ Private = (PXEBC_PRIVATE_DATA *) Context;\r
+ Mode = &Private->Mode;\r
+ Status = Private->IcmpErrorRcvToken.Status;\r
+ RxData = Private->IcmpErrorRcvToken.Packet.RxData;\r
+ Ip4 = Private->Ip4;\r
+\r
+ if (EFI_ABORTED == Status) {\r
+ //\r
+ // The reception is actively aborted by the consumer, directly return.\r
+ //\r
+ return;\r
+ }\r
+\r
+ if ((EFI_SUCCESS != Status) || (NULL == RxData)) {\r
+ //\r
+ // Only process the normal packets and the icmp error packets, if RxData is NULL\r
+ // with Status == EFI_SUCCESS or EFI_ICMP_ERROR, just resume the receive although\r
+ // this should be a bug of the low layer (IP).\r
+ //\r
+ goto Resume;\r
+ }\r
+\r
+ if ((EFI_IP4 (RxData->Header->SourceAddress) != 0) &&\r
+ !Ip4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
+ //\r
+ // The source address is not zero and it's not a unicast IP address, discard it.\r
+ //\r
+ goto CleanUp;\r
+ }\r
+\r
+ if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {\r
+ //\r
+ // The dest address is not equal to Station Ip address, discard it.\r
+ //\r
+ goto CleanUp;\r
+ }\r
+\r
+ //\r
+ // Constructor ICMP error packet\r
+ //\r
+ CopiedLen = 0;\r
+ CopiedPointer = (UINT8 *) &Mode->IcmpError;\r
+\r
+ for (Index = 0; Index < RxData->FragmentCount; Index ++) {\r
+ CopiedLen += RxData->FragmentTable[Index].FragmentLength;\r
+ if (CopiedLen <= sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR)) {\r
+ CopyMem (CopiedPointer, RxData->FragmentTable[Index].FragmentBuffer, RxData->FragmentTable[Index].FragmentLength);\r
+ } else {\r
+ CopyMem (CopiedPointer, RxData->FragmentTable[Index].FragmentBuffer, CopiedLen - sizeof (EFI_PXE_BASE_CODE_ICMP_ERROR));\r
+ }\r
+ CopiedPointer += CopiedLen;\r
+ }\r
+\r
+ goto Resume;\r
+\r
+CleanUp:\r
+ gBS->SignalEvent (RxData->RecycleSignal);\r
+\r
+Resume:\r
+ Ip4->Receive (Ip4, &(Private->IcmpErrorRcvToken));\r
+}\r
+\r
+/**\r
+ Request IcmpErrorListenHandlerDpc as a DPC at TPL_CALLBACK\r
+\r
+ @param Event The event signaled.\r
+ @param Context The context passed in by the event notifier.\r
+\r
+ @return None.\r
+\r
+**/\r
+STATIC\r
+VOID\r
+EFIAPI\r
+IcmpErrorListenHandler (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ //\r
+ // Request IpIoListenHandlerDpc as a DPC at TPL_CALLBACK\r
+ //\r
+ NetLibQueueDpc (TPL_CALLBACK, IcmpErrorListenHandlerDpc, Context);\r
+}\r