/** @file\r
Support functions implementation for UefiPxeBc Driver.\r
\r
- Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>\r
\r
- This program and the accompanying materials\r
- are licensed and made available under the terms and conditions of the BSD License\r
- which accompanies this distribution. The full text of the license may be found at\r
- http://opensource.org/licenses/bsd-license.php.\r
-\r
- THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
- WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
\r
**/\r
\r
#include "PxeBcImpl.h"\r
\r
\r
-\r
/**\r
- This function returns SMBIOS string given the string number.\r
-\r
- @param[in] Smbios The pointer to the SMBIOS structure\r
- @param[in] StringNumber String number to return. 0 is used to skip all\r
- strings and point to the next SMBIOS structure.\r
-\r
- @return String The pointer to the next SMBIOS structure if\r
- StringNumber == 0.\r
-\r
-**/\r
-CHAR8 *\r
-PxeBcGetSmbiosString (\r
- IN SMBIOS_STRUCTURE_POINTER *Smbios,\r
- IN UINT16 StringNumber\r
- )\r
-{\r
- UINT16 Index;\r
- CHAR8 *String;\r
-\r
- //\r
- // Skip over formatted section.\r
- //\r
- String = (CHAR8 *) (Smbios->Raw + Smbios->Hdr->Length);\r
-\r
- //\r
- // Look through unformated section.\r
- //\r
- for (Index = 1; Index <= StringNumber || StringNumber == 0; Index++) {\r
- if (StringNumber == Index) {\r
- return String;\r
- }\r
-\r
- //\r
- // Skip zero string.\r
- //\r
- while (*String != 0) {\r
- String++;\r
- }\r
- String++;\r
-\r
- if (*String == 0) {\r
- //\r
- // If double NULL then we are done.\r
- // Return pointer to next structure in Smbios.\r
- // if you pass in a 0 you will always get here\r
- //\r
- Smbios->Raw = (UINT8 *)++String;\r
- return NULL;\r
- }\r
- }\r
-\r
- return NULL;\r
-}\r
-\r
-\r
-/**\r
- This function obtains the system guid and the serial number from the smbios table.\r
-\r
- @param[out] SystemGuid The pointer of the returned system guid.\r
-\r
- @retval EFI_SUCCESS Successfully obtained the system guid.\r
- @retval EFI_NOT_FOUND Did not find the SMBIOS table.\r
-\r
-**/\r
-EFI_STATUS\r
-PxeBcGetSystemGuid (\r
- OUT EFI_GUID *SystemGuid\r
- )\r
-{\r
- EFI_STATUS Status;\r
- SMBIOS_TABLE_ENTRY_POINT *SmbiosTable;\r
- SMBIOS_STRUCTURE_POINTER Smbios;\r
- SMBIOS_STRUCTURE_POINTER SmbiosEnd;\r
- UINT16 Index;\r
-\r
- SmbiosTable = NULL;\r
- Status = EfiGetSystemConfigurationTable (&gEfiSmbiosTableGuid, (VOID **) &SmbiosTable);\r
-\r
- if (EFI_ERROR (Status) || SmbiosTable == NULL) {\r
- return EFI_NOT_FOUND;\r
- }\r
-\r
- Smbios.Hdr = (SMBIOS_STRUCTURE *) (UINTN) SmbiosTable->TableAddress;\r
- SmbiosEnd.Raw = (UINT8 *) (UINTN) (SmbiosTable->TableAddress + SmbiosTable->TableLength);\r
-\r
- for (Index = 0; Index < SmbiosTable->TableLength; Index++) {\r
- if (Smbios.Hdr->Type == 1) {\r
- if (Smbios.Hdr->Length < 0x19) {\r
- //\r
- // Older version did not support Guid and Serial number\r
- //\r
- continue;\r
- }\r
- //\r
- // SMBIOS tables are byte packed so we need to do a byte copy to\r
- // prevend alignment faults on Itanium-based platform.\r
- //\r
- CopyMem (SystemGuid, &Smbios.Type1->Uuid, sizeof (EFI_GUID));\r
- PxeBcGetSmbiosString (&Smbios, Smbios.Type1->SerialNumber);\r
-\r
- return EFI_SUCCESS;\r
- }\r
- //\r
- // Make Smbios point to the next record\r
- //\r
- PxeBcGetSmbiosString (&Smbios, 0);\r
-\r
- if (Smbios.Raw >= SmbiosEnd.Raw) {\r
- //\r
- // SMBIOS 2.1 incorrectly stated the length of SmbiosTable as 0x1e.\r
- // given this we must double check against the length of the structure.\r
- //\r
- return EFI_SUCCESS;\r
- }\r
- }\r
-\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-\r
-/**\r
- Flush the previous configration using the new station Ip address.\r
+ Flush the previous configuration using the new station Ip address.\r
\r
@param[in] Private The pointer to the PxeBc private data.\r
@param[in] StationIp The pointer to the station Ip address.\r
\r
**/\r
EFI_STATUS\r
-PxeBcFlushStaionIp (\r
+PxeBcFlushStationIp (\r
PXEBC_PRIVATE_DATA *Private,\r
- EFI_IP_ADDRESS *StationIp,\r
+ EFI_IP_ADDRESS *StationIp, OPTIONAL\r
EFI_IP_ADDRESS *SubnetMask OPTIONAL\r
)\r
{\r
EFI_PXE_BASE_CODE_MODE *Mode;\r
EFI_STATUS Status;\r
-\r
- ASSERT (StationIp != NULL);\r
+ EFI_ARP_CONFIG_DATA ArpConfigData;\r
\r
Mode = Private->PxeBc.Mode;\r
Status = EFI_SUCCESS;\r
+ ZeroMem (&ArpConfigData, sizeof (EFI_ARP_CONFIG_DATA));\r
\r
- if (Mode->UsingIpv6) {\r
-\r
+ if (Mode->UsingIpv6 && StationIp != NULL) {\r
+ //\r
+ // Overwrite Udp6CfgData/Ip6CfgData StationAddress.\r
+ //\r
CopyMem (&Private->Udp6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));\r
CopyMem (&Private->Ip6CfgData.StationAddress, StationIp, sizeof (EFI_IPv6_ADDRESS));\r
\r
}\r
\r
Status = Private->Ip6->Receive (Private->Ip6, &Private->Icmp6Token);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
-\r
} else {\r
- ASSERT (SubnetMask != NULL);\r
- CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));\r
- CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
- CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));\r
- CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ if (StationIp != NULL) {\r
+ //\r
+ // Reconfigure the ARP instance with station Ip address.\r
+ //\r
+ ArpConfigData.SwAddressType = 0x0800;\r
+ ArpConfigData.SwAddressLength = (UINT8) sizeof (EFI_IPv4_ADDRESS);\r
+ ArpConfigData.StationAddress = StationIp;\r
\r
- //\r
- // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.\r
- //\r
- Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);\r
- Private->Ip4->Configure (Private->Ip4, NULL);\r
+ Private->Arp->Configure (Private->Arp, NULL);\r
+ Private->Arp->Configure (Private->Arp, &ArpConfigData);\r
\r
- Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
+ //\r
+ // Overwrite Udp4CfgData/Ip4CfgData StationAddress.\r
+ //\r
+ CopyMem (&Private->Udp4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Private->Ip4CfgData.StationAddress, StationIp, sizeof (EFI_IPv4_ADDRESS));\r
}\r
\r
- Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
+ if (SubnetMask != NULL) {\r
+ //\r
+ // Overwrite Udp4CfgData/Ip4CfgData SubnetMask.\r
+ //\r
+ CopyMem (&Private->Udp4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
+ CopyMem (&Private->Ip4CfgData.SubnetMask, SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
}\r
\r
+ if (StationIp != NULL && SubnetMask != NULL) {\r
+ //\r
+ // Updated the route table.\r
+ //\r
+ Mode->RouteTableEntries = 1;\r
+ Mode->RouteTable[0].IpAddr.Addr[0] = StationIp->Addr[0] & SubnetMask->Addr[0];\r
+ Mode->RouteTable[0].SubnetMask.Addr[0] = SubnetMask->Addr[0];\r
+ Mode->RouteTable[0].GwAddr.Addr[0] = 0;\r
+ }\r
+\r
+ if (StationIp != NULL || SubnetMask != NULL) {\r
+ //\r
+ // Reconfigure the Ip4 instance to capture background ICMP packets with new station Ip address.\r
+ //\r
+ Private->Ip4->Cancel (Private->Ip4, &Private->IcmpToken);\r
+ Private->Ip4->Configure (Private->Ip4, NULL);\r
+\r
+ Status = Private->Ip4->Configure (Private->Ip4, &Private->Ip4CfgData);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ }\r
+\r
+ Status = Private->Ip4->Receive (Private->Ip4, &Private->IcmpToken);\r
+ }\r
}\r
\r
ON_EXIT:\r
\r
@param Mode The pointer to EFI_PXE_BASE_CODE_MODE.\r
@param Ip4Addr The Ip4 address for resolution.\r
- @param MacAddress The resoluted MAC address if the resolution is successful.\r
+ @param MacAddress The resolved MAC address if the resolution is successful.\r
The value is undefined if the resolution fails.\r
\r
@retval TRUE Found an matched entry.\r
//\r
// The return status should be recognized as EFI_ICMP_ERROR.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
if (EFI_IP4 (RxData->Header->SourceAddress) != 0 &&\r
- !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), 0)) {\r
+ (NTOHL (Mode->SubnetMask.Addr[0]) != 0) &&\r
+ IP4_NET_EQUAL (NTOHL(Mode->StationIp.Addr[0]), EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0])) &&\r
+ !NetIp4IsUnicast (EFI_NTOHL (RxData->Header->SourceAddress), NTOHL (Mode->SubnetMask.Addr[0]))) {\r
//\r
// The source address of the received packet should be a valid unicast address.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
if (!EFI_IP4_EQUAL (&RxData->Header->DestinationAddress, &Mode->StationIp.v4)) {\r
//\r
// The destination address of the received packet should be equal to the host address.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
- if (RxData->Header->Protocol != EFI_IP_PROTO_ICMP) {\r
- //\r
- // The protocol value in the header of the receveid packet should be EFI_IP_PROTO_ICMP.\r
- //\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
- }\r
+ //\r
+ // The protocol has been configured to only receive ICMP packet.\r
+ //\r
+ ASSERT (RxData->Header->Protocol == EFI_IP_PROTO_ICMP);\r
\r
Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);\r
\r
//\r
// The type of the receveid ICMP message should be ICMP_ERROR_MESSAGE.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
//\r
IcmpError += CopiedLen;\r
}\r
\r
+ON_RECYCLE:\r
+ gBS->SignalEvent (RxData->RecycleSignal);\r
+\r
ON_EXIT:\r
Private->IcmpToken.Status = EFI_NOT_READY;\r
Ip4->Receive (Ip4, &Private->IcmpToken);\r
//\r
// The return status should be recognized as EFI_ICMP_ERROR.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
if (!NetIp6IsValidUnicast (&RxData->Header->SourceAddress)) {\r
//\r
// The source address of the received packet should be a valid unicast address.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
if (!NetIp6IsUnspecifiedAddr (&Mode->StationIp.v6) &&\r
//\r
// The destination address of the received packet should be equal to the host address.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
- if (RxData->Header->NextHeader != IP6_ICMP) {\r
- //\r
- // The nextheader in the header of the receveid packet should be IP6_ICMP.\r
- //\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
- }\r
+ //\r
+ // The protocol has been configured to only receive ICMP packet.\r
+ //\r
+ ASSERT (RxData->Header->NextHeader == IP6_ICMP);\r
\r
Type = *((UINT8 *) RxData->FragmentTable[0].FragmentBuffer);\r
\r
if (Type != ICMP_V6_DEST_UNREACHABLE &&\r
Type != ICMP_V6_PACKET_TOO_BIG &&\r
- Type != ICMP_V6_PACKET_TOO_BIG &&\r
+ Type != ICMP_V6_TIME_EXCEEDED &&\r
Type != ICMP_V6_PARAMETER_PROBLEM) {\r
//\r
// The type of the receveid packet should be an ICMP6 error message.\r
//\r
- gBS->SignalEvent (RxData->RecycleSignal);\r
- goto ON_EXIT;\r
+ goto ON_RECYCLE;\r
}\r
\r
//\r
Icmp6Error += CopiedLen;\r
}\r
\r
+ON_RECYCLE:\r
+ gBS->SignalEvent (RxData->RecycleSignal);\r
+\r
ON_EXIT:\r
Private->Icmp6Token.Status = EFI_NOT_READY;\r
Ip6->Receive (Ip6, &Private->Icmp6Token);\r
@param[in, out] SrcPort The pointer to the source port.\r
@param[in] DoNotFragment If TRUE, fragment is not enabled.\r
Otherwise, fragment is enabled.\r
+ @param[in] Ttl The time to live field of the IP header.\r
+ @param[in] ToS The type of service field of the IP header.\r
\r
@retval EFI_SUCCESS Successfully configured this instance.\r
@retval Others Failed to configure this instance.\r
IN EFI_IPv4_ADDRESS *SubnetMask,\r
IN EFI_IPv4_ADDRESS *Gateway,\r
IN OUT UINT16 *SrcPort,\r
- IN BOOLEAN DoNotFragment\r
+ IN BOOLEAN DoNotFragment,\r
+ IN UINT8 Ttl,\r
+ IN UINT8 ToS\r
)\r
{\r
EFI_UDP4_CONFIG_DATA Udp4CfgData;\r
\r
Udp4CfgData.TransmitTimeout = PXEBC_DEFAULT_LIFETIME;\r
Udp4CfgData.ReceiveTimeout = PXEBC_DEFAULT_LIFETIME;\r
- Udp4CfgData.TypeOfService = DEFAULT_ToS;\r
- Udp4CfgData.TimeToLive = DEFAULT_TTL;\r
+ Udp4CfgData.TypeOfService = ToS;\r
+ Udp4CfgData.TimeToLive = Ttl;\r
Udp4CfgData.AllowDuplicatePort = TRUE;\r
Udp4CfgData.DoNotFragment = DoNotFragment;\r
\r
/**\r
Check the received packet using the destination port.\r
\r
- @param[in] PxeBcMode The pointer to the mode data of PxeBc.\r
+ @param[in] Mode The pointer to the mode data of PxeBc.\r
@param[in] Session The pointer to the current UDPv4 session.\r
@param[in, out] DestPort The pointer to the destination port.\r
@param[in] OpFlags Operation flag for UdpRead/UdpWrite.\r
Token->Status == EFI_NOT_READY &&\r
EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
//\r
- // Poll the token utill reply/ICMPv6 error message received or timeout.\r
+ // Poll the token until reply/ICMPv6 error message received or timeout.\r
//\r
Udp4->Poll (Udp4);\r
if (Token->Status == EFI_ICMP_ERROR ||\r
Token->Status == EFI_NOT_READY &&\r
EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
//\r
- // Poll the token utill reply/ICMPv6 error message received or timeout.\r
+ // Poll the token until reply/ICMPv6 error message received or timeout.\r
//\r
Udp6->Poll (Udp6);\r
if (Token->Status == EFI_ICMP_ERROR ||\r
{\r
UINTN Remainder;\r
\r
- while (Length > 0) {\r
- Length--;\r
+ for (; Length > 0; Length--) {\r
Remainder = Number % 10;\r
Number /= 10;\r
- Buffer[Length] = (UINT8) ('0' + Remainder);\r
+ Buffer[Length - 1] = (UINT8) ('0' + Remainder);\r
}\r
}\r
\r
\r
@param[in] Number Numeric value to be converted.\r
@param[in] Buffer The pointer to the buffer for ASCII string.\r
+ @param[in] BufferSize The maxsize of the buffer.\r
\r
@return Length The actual length of the ASCII string.\r
\r
UINTN\r
PxeBcUintnToAscDec (\r
IN UINTN Number,\r
- IN UINT8 *Buffer\r
+ IN UINT8 *Buffer,\r
+ IN UINTN BufferSize\r
)\r
{\r
UINTN Index;\r
Number = (UINTN) (Number / 10);\r
} while (Number != 0);\r
\r
- AsciiStrCpy ((CHAR8 *) Buffer, &TempStr[Index]);\r
+ AsciiStrCpyS ((CHAR8 *) Buffer, BufferSize, &TempStr[Index]);\r
\r
Length = AsciiStrLen ((CHAR8 *) Buffer);\r
\r
\r
return EFI_INVALID_PARAMETER;\r
}\r
+\r
+/**\r
+ Calculate the elapsed time.\r
+\r
+ @param[in] Private The pointer to PXE private data\r
+\r
+**/\r
+VOID\r
+CalcElapsedTime (\r
+ IN PXEBC_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_TIME Time;\r
+ UINT64 CurrentStamp;\r
+ UINT64 ElapsedTimeValue;\r
+\r
+ //\r
+ // Generate a time stamp of the centiseconds from 1900/1/1, assume 30day/month.\r
+ //\r
+ ZeroMem (&Time, sizeof (EFI_TIME));\r
+ gRT->GetTime (&Time, NULL);\r
+ CurrentStamp = MultU64x32 (\r
+ ((((UINT32)(Time.Year - 1900) * 360 + (Time.Month - 1) * 30 + (Time.Day - 1)) * 24 + Time.Hour) * 60 + Time.Minute) * 60 + Time.Second,\r
+ 100\r
+ ) +\r
+ DivU64x32 (\r
+ Time.Nanosecond,\r
+ 10000000\r
+ );\r
+\r
+ //\r
+ // Sentinel value of 0 means that this is the first DHCP packet that we are\r
+ // sending and that we need to initialize the value. First DHCP Solicit\r
+ // gets 0 elapsed-time. Otherwise, calculate based on StartTime.\r
+ //\r
+ if (Private->ElapsedTime == 0) {\r
+ Private->ElapsedTime = CurrentStamp;\r
+ } else {\r
+ ElapsedTimeValue = CurrentStamp - Private->ElapsedTime;\r
+\r
+ //\r
+ // If elapsed time cannot fit in two bytes, set it to 0xffff.\r
+ //\r
+ if (ElapsedTimeValue > 0xffff) {\r
+ ElapsedTimeValue = 0xffff;\r
+ }\r
+ //\r
+ // Save the elapsed time\r
+ //\r
+ Private->ElapsedTime = ElapsedTimeValue;\r
+ }\r
+}\r
+\r