\r
#include "PxeBcImpl.h"\r
\r
+/**\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
\r
/**\r
GC_NOTO: Add function description\r
EFI_PXE_BASE_CODE_MODE *Mode;\r
EFI_STATUS Status;\r
\r
+ CpuDeadLoop ();\r
if (This == NULL) {\r
return EFI_INVALID_PARAMETER;\r
}\r
Mode->ToS = DEFAULT_ToS;\r
Mode->AutoArp = TRUE;\r
\r
- return EFI_SUCCESS;\r
+ //\r
+ // Create the event for Arp Cache checking.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ ArpCacheUpdateTimeout,\r
+ This,\r
+ &Private->GetArpCacheEvent\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Start the timeout timer event.\r
+ //\r
+ Status = gBS->SetTimer (\r
+ Private->GetArpCacheEvent,\r
+ TimerPeriodic,\r
+ TICKS_PER_SECOND\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // Create ICMP error receiving event\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_NOTIFY,\r
+ IcmpErrorListenHandler,\r
+ Private,\r
+ &(Private->IcmpErrorRcvToken.Event)\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4ConfigData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ //\r
+ // start to listen incoming packet\r
+ //\r
+ Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpErrorRcvToken);\r
+ if (!EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ON_EXIT:\r
+ Private->Ip4->Configure (Private->Ip4, NULL);\r
+\r
+ if (Private->IcmpErrorRcvToken.Event != NULL) {\r
+ gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);\r
+ }\r
+\r
+ if (Private->GetArpCacheEvent != NULL) {\r
+ gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);\r
+ gBS->CloseEvent (Private->GetArpCacheEvent);\r
+ }\r
+\r
+ Mode->Started = FALSE;\r
+ Mode->TTL = 0;\r
+ Mode->ToS = 0;\r
+ Mode->AutoArp = FALSE;\r
+\r
+ return Status;\r
}\r
\r
\r
return EFI_NOT_STARTED;\r
}\r
\r
+ Private->Ip4->Cancel (Private->Ip4, NULL);\r
+ //\r
+ // Dispatch the DPCs queued by the NotifyFunction of the canceled rx token's\r
+ // events.\r
+ //\r
+ NetLibDispatchDpc ();\r
+\r
+ Private->Ip4->Configure (Private->Ip4, NULL);\r
+\r
+ //\r
+ // Close the ICMP error receiving event.\r
+ //\r
+ gBS->CloseEvent (Private->IcmpErrorRcvToken.Event);\r
+\r
+ //\r
+ // Cancel the TimeoutEvent timer.\r
+ //\r
+ gBS->SetTimer (Private->GetArpCacheEvent, TimerCancel, 0);\r
+\r
+ //\r
+ // Close the TimeoutEvent event.\r
+ //\r
+ gBS->CloseEvent (Private->GetArpCacheEvent);\r
+\r
Mode->Started = FALSE;\r
\r
+\r
//\r
// Reset and leave joined groups\r
//\r
if (!Mode->Started) {\r
return EFI_NOT_STARTED;\r
}\r
+\r
+ Mode->IcmpErrorReceived = FALSE;\r
+\r
//\r
// Initialize the DHCP options and build the option list\r
//\r
//\r
continue;\r
}\r
+ if (Status == EFI_ICMP_ERROR) {\r
+ Mode->IcmpErrorReceived = TRUE;\r
+ }\r
//\r
// Other error status means the DHCP really fails.\r
//\r
\r
Private->Arp->Configure (Private->Arp, NULL);\r
Private->Arp->Configure (Private->Arp, &ArpConfigData);\r
+\r
+ //\r
+ // Updated the route table. Fill the first entry.\r
+ //\r
+ Mode->RouteTableEntries = 1;\r
+ Mode->RouteTable[0].IpAddr.Addr[0] = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];\r
+ Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];\r
+ Mode->RouteTable[0].GwAddr.Addr[0] = 0;\r
+\r
+ //\r
+ // Create the default route entry if there is a default router.\r
+ //\r
+ if (Private->GatewayIp.Addr[0] != 0) {\r
+ Mode->RouteTableEntries = 2;\r
+ Mode->RouteTable[1].IpAddr.Addr[0] = 0;\r
+ Mode->RouteTable[1].SubnetMask.Addr[0] = 0;\r
+ Mode->RouteTable[1].GwAddr.Addr[0] = Private->GatewayIp.Addr[0];\r
+ }\r
}\r
}\r
\r
return EFI_NOT_STARTED;\r
}\r
\r
+ Mode->IcmpErrorReceived = FALSE;\r
+\r
//\r
// If layer isn't EFI_PXE_BASE_CODE_BOOT_LAYER_INITIAL,\r
// use the previous setting;\r
}\r
\r
if (EFI_ERROR (Status) || !Mode->PxeReplyReceived || (!Mode->PxeBisReplyReceived && UseBis)) {\r
-\r
- Status = EFI_DEVICE_ERROR;\r
+ if (Status == EFI_ICMP_ERROR) {\r
+ Mode->IcmpErrorReceived = TRUE;\r
+ } else {\r
+ Status = EFI_DEVICE_ERROR;\r
+ }\r
} else {\r
PxeBcParseCachedDhcpPacket (&Private->PxeReply);\r
}\r
PXEBC_PRIVATE_DATA *Private;\r
EFI_MTFTP4_CONFIG_DATA Mtftp4Config;\r
EFI_STATUS Status;\r
+ EFI_PXE_BASE_CODE_MODE *Mode;\r
+ EFI_MAC_ADDRESS TempMacAddr;\r
\r
if ((This == NULL) ||\r
(Filename == NULL) ||\r
\r
Status = EFI_DEVICE_ERROR;\r
Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
+ Mode = &Private->Mode;\r
+\r
+ if (!Mode->AutoArp) {\r
+ //\r
+ // If AutoArp is set false, check arp cache\r
+ //\r
+ UpdateArpCache (This);\r
+ if (!FindInArpCache (Mode, &ServerIp->v4, &TempMacAddr)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ Mode->TftpErrorReceived = FALSE;\r
+ Mode->IcmpErrorReceived = FALSE;\r
\r
Mtftp4Config.UseDefaultSetting = FALSE;\r
Mtftp4Config.TimeoutValue = PXEBC_MTFTP_TIMEOUT;\r
break;\r
}\r
\r
+ if (Status == EFI_ICMP_ERROR) {\r
+ Mode->IcmpErrorReceived = TRUE;\r
+ }\r
+\r
return Status;\r
}\r
\r
EFI_STATUS Status;\r
BOOLEAN IsDone;\r
UINT16 RandomSrcPort;\r
+ EFI_PXE_BASE_CODE_MODE *Mode;\r
+ EFI_MAC_ADDRESS TempMacAddr;\r
\r
IsDone = FALSE;\r
\r
\r
Private = PXEBC_PRIVATE_DATA_FROM_PXEBC (This);\r
Udp4 = Private->Udp4;\r
+ Mode = &Private->Mode;\r
\r
if (!Private->AddressIsOk && (SrcIp == NULL)) {\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
+ if (!Mode->AutoArp) {\r
+ //\r
+ // If AutoArp is set false, check arp cache\r
+ //\r
+ UpdateArpCache (This);\r
+ if (!FindInArpCache (Mode, &DestIp->v4, &TempMacAddr)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ }\r
+\r
+ Mode->IcmpErrorReceived = FALSE;\r
+\r
if (SrcIp == NULL) {\r
SrcIp = &Private->StationIp;\r
\r
\r
Status = Udp4->Transmit (Udp4, &Token);\r
if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_ICMP_ERROR) {\r
+ Mode->IcmpErrorReceived = TRUE;\r
+ }\r
goto ON_EXIT;\r
}\r
\r
\r
CopyMem (&DestIp4Address, &Session->DestinationAddress, sizeof (DestIp4Address));\r
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_PROMISCUOUS_MULTICAST) &&\r
- IP4_IS_MULTICAST (NTOHL (EFI_IP4 (DestIp4Address)))\r
+ IP4_IS_MULTICAST (EFI_NTOHL (DestIp4Address))\r
) {\r
return TRUE;\r
}\r
\r
CopyMem (&Ip4Address, &PxeBcMode->StationIp.v4, sizeof (Ip4Address));\r
if ((PxeBcMode->IpFilter.Filters & EFI_PXE_BASE_CODE_IP_FILTER_STATION_IP) &&\r
- EFI_IP4_EQUAL (&PxeBcMode->StationIp.v4, &DestIp4Address)\r
+ EFI_IP4_EQUAL (&Ip4Address, &DestIp4Address)\r
) {\r
return TRUE;\r
}\r
return EFI_NOT_STARTED;\r
}\r
\r
+ Mode->IcmpErrorReceived = FALSE;\r
+\r
Status = gBS->CreateEvent (\r
EVT_NOTIFY_SIGNAL,\r
TPL_NOTIFY,\r
IsDone = FALSE;\r
Status = Udp4->Receive (Udp4, &Token);\r
if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_ICMP_ERROR) {\r
+ Mode->IcmpErrorReceived = TRUE;\r
+ }\r
goto ON_EXIT;\r
}\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
\r
- Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, NULL, &TempMacAddr);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
+ Mode->IcmpErrorReceived = FALSE;\r
+\r
+ if (!Mode->AutoArp) {\r
+ //\r
+ // If AutoArp is set false, check arp cache\r
+ //\r
+ UpdateArpCache (This);\r
+ if (!FindInArpCache (Mode, &IpAddr->v4, &TempMacAddr)) {\r
+ return EFI_DEVICE_ERROR;\r
+ }\r
+ } else {\r
+ Status = Private->Arp->Request (Private->Arp, &IpAddr->v4, NULL, &TempMacAddr);\r
+ if (EFI_ERROR (Status)) {\r
+ if (Status == EFI_ICMP_ERROR) {\r
+ Mode->IcmpErrorReceived = TRUE;\r
+ }\r
+ return Status;\r
+ }\r
}\r
\r
if (MacAddr != NULL) {\r
}\r
\r
if (NewStationIp != NULL) {\r
- Mode->StationIp = *NewStationIp;\r
+ Mode->StationIp = *NewStationIp;\r
+ Private->StationIp = *NewStationIp;\r
}\r
\r
if (NewSubnetMask != NULL) {\r
- Mode->SubnetMask = *NewSubnetMask;\r
+ Mode->SubnetMask = *NewSubnetMask;\r
+ Private->SubnetMask = *NewSubnetMask;\r
}\r
\r
Private->AddressIsOk = TRUE;\r
\r
Private->Arp->Configure (Private->Arp, NULL);\r
Private->Arp->Configure (Private->Arp, &ArpConfigData);\r
+\r
+ //\r
+ // Update the route table.\r
+ //\r
+ Mode->RouteTableEntries = 1;\r
+ Mode->RouteTable[0].IpAddr.Addr[0] = Private->StationIp.Addr[0] & Private->SubnetMask.Addr[0];\r
+ Mode->RouteTable[0].SubnetMask.Addr[0] = Private->SubnetMask.Addr[0];\r
+ Mode->RouteTable[0].GwAddr.Addr[0] = 0;\r
}\r
\r
return EFI_SUCCESS;\r
BlockSize = 0x8000;\r
Status = EFI_DEVICE_ERROR;\r
\r
+ CpuDeadLoop ();\r
if (This == NULL || BufferSize == NULL) {\r
\r
return EFI_INVALID_PARAMETER;\r