Mike Beaton f30d41230d OpenNetworkBoot: Add support for setting static IPv4 address NVRAM variable
Normally only useful for our HttpBootDxe, which supports HTTP
boot from static IP address as long as URI is also pre-specified.

The NVRAM setting should affect normal EDK II derived network stacks
and will configure a static IP on the card, but this will later be
ignored and overridden by DHCP when PXE or HTTP boot is started in the
standard network stack.

Signed-off-by: Mike Beaton <mjsbeaton@gmail.com>
2024-12-22 14:09:25 +00:00

298 lines
6.3 KiB
C

/** @file
IPv4 utilities.
Methods from:
- NetworkPkg/Ip4Dxe/Ip4Common.c
- NetworkPkg/Ip4Dxe/Ip4Config2Nv.c
Copyright (c) 2005 - 2018, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "NetworkBootInternal.h"
/**
Validate that Ip/Netmask pair is OK to be used as station
address. Only continuous netmasks are supported. and check
that StationAddress is a unicast address on the network.
@param[in] Ip The IP address to validate.
@param[in] Netmask The netmask of the IP.
@retval TRUE The Ip/Netmask pair is valid.
@retval FALSE The Ip/Netmask pair is invalid.
**/
BOOLEAN
Ip4StationAddressValid (
IN IP4_ADDR Ip,
IN IP4_ADDR Netmask
)
{
//
// Only support the station address with 0.0.0.0/0 to enable DHCP client.
//
if (Netmask == IP4_ALLZERO_ADDRESS) {
return (BOOLEAN)(Ip == IP4_ALLZERO_ADDRESS);
}
//
// Only support the continuous net masks
//
if (NetGetMaskLength (Netmask) == (IP4_MASK_MAX + 1)) {
return FALSE;
}
//
// Station address can't be class D or class E address
//
if (NetGetIpClass (Ip) > IP4_ADDR_CLASSC) {
return FALSE;
}
return NetIp4IsUnicast (Ip, Netmask);
}
/**
Calculate the prefix length of the IPv4 subnet mask.
@param[in] SubnetMask The IPv4 subnet mask.
@return The prefix length of the subnet mask.
@retval 0 Other errors as indicated.
**/
UINT8
GetSubnetMaskPrefixLength (
IN EFI_IPv4_ADDRESS *SubnetMask
)
{
UINT8 Len;
UINT32 ReverseMask;
//
// The SubnetMask is in network byte order.
//
ReverseMask = SwapBytes32 (*(UINT32 *)&SubnetMask[0]);
//
// Reverse it.
//
ReverseMask = ~ReverseMask;
if ((ReverseMask & (ReverseMask + 1)) != 0) {
return 0;
}
Len = 0;
while (ReverseMask != 0) {
ReverseMask = ReverseMask >> 1;
Len++;
}
return (UINT8)(32 - Len);
}
/**
Convert the decimal dotted IPv4 address into the binary IPv4 address.
@param[in] Str The UNICODE string.
@param[out] Ip The storage to return the IPv4 address.
@retval EFI_SUCCESS The binary IP address is returned in Ip.
@retval EFI_INVALID_PARAMETER The IP string is malformatted.
**/
EFI_STATUS
Ip4Config2StrToIp (
IN CHAR16 *Str,
OUT EFI_IPv4_ADDRESS *Ip
)
{
UINTN Index;
UINTN Number;
Index = 0;
while (*Str != L'\0') {
if (Index > 3) {
return EFI_INVALID_PARAMETER;
}
Number = 0;
while ((*Str >= L'0') && (*Str <= L'9')) {
Number = Number * 10 + (*Str - L'0');
Str++;
}
if (Number > 0xFF) {
return EFI_INVALID_PARAMETER;
}
Ip->Addr[Index] = (UINT8)Number;
if ((*Str != L'\0') && (*Str != L'.')) {
//
// The current character should be either the NULL terminator or
// the dot delimiter.
//
return EFI_INVALID_PARAMETER;
}
if (*Str == L'.') {
//
// Skip the delimiter.
//
Str++;
}
Index++;
}
if (Index != 4) {
return EFI_INVALID_PARAMETER;
}
return EFI_SUCCESS;
}
/**
Convert the decimal dotted IPv4 addresses separated by space into the binary IPv4 address list.
@param[in] Str The UNICODE string contains IPv4 addresses.
@param[out] PtrIpList The storage to return the IPv4 address list.
@param[out] IpCount The size of the IPv4 address list.
@retval EFI_SUCCESS The binary IP address list is returned in PtrIpList.
@retval EFI_OUT_OF_RESOURCES Error occurs in allocating memory.
@retval EFI_INVALID_PARAMETER The IP string is malformatted.
**/
EFI_STATUS
Ip4Config2StrToIpList (
IN CHAR16 *Str,
OUT EFI_IPv4_ADDRESS **PtrIpList,
OUT UINTN *IpCount
)
{
UINTN BeginIndex;
UINTN EndIndex;
UINTN Index;
UINTN IpIndex;
CHAR16 *StrTemp;
BOOLEAN SpaceTag;
BeginIndex = 0;
EndIndex = BeginIndex;
Index = 0;
IpIndex = 0;
StrTemp = NULL;
SpaceTag = TRUE;
*PtrIpList = NULL;
*IpCount = 0;
if (Str == NULL) {
return EFI_SUCCESS;
}
//
// Get the number of Ip.
//
while (*(Str + Index) != L'\0') {
if (*(Str + Index) == L' ') {
SpaceTag = TRUE;
} else {
if (SpaceTag) {
(*IpCount)++;
SpaceTag = FALSE;
}
}
Index++;
}
if (*IpCount == 0) {
return EFI_SUCCESS;
}
//
// Allocate buffer for IpList.
//
*PtrIpList = AllocateZeroPool (*IpCount * sizeof (EFI_IPv4_ADDRESS));
if (*PtrIpList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
//
// Get IpList from Str.
//
Index = 0;
while (*(Str + Index) != L'\0') {
if (*(Str + Index) == L' ') {
if (!SpaceTag) {
StrTemp = AllocateZeroPool ((EndIndex - BeginIndex + 1) * sizeof (CHAR16));
if (StrTemp == NULL) {
FreePool (*PtrIpList);
*PtrIpList = NULL;
*IpCount = 0;
return EFI_OUT_OF_RESOURCES;
}
CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof (CHAR16));
*(StrTemp + (EndIndex - BeginIndex)) = L'\0';
if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
FreePool (StrTemp);
FreePool (*PtrIpList);
*PtrIpList = NULL;
*IpCount = 0;
return EFI_INVALID_PARAMETER;
}
BeginIndex = EndIndex;
IpIndex++;
FreePool (StrTemp);
}
BeginIndex++;
EndIndex++;
SpaceTag = TRUE;
} else {
EndIndex++;
SpaceTag = FALSE;
}
Index++;
if (*(Str + Index) == L'\0') {
if (!SpaceTag) {
StrTemp = AllocateZeroPool ((EndIndex - BeginIndex + 1) * sizeof (CHAR16));
if (StrTemp == NULL) {
FreePool (*PtrIpList);
*PtrIpList = NULL;
*IpCount = 0;
return EFI_OUT_OF_RESOURCES;
}
CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof (CHAR16));
*(StrTemp + (EndIndex - BeginIndex)) = L'\0';
if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
FreePool (StrTemp);
FreePool (*PtrIpList);
*PtrIpList = NULL;
*IpCount = 0;
return EFI_INVALID_PARAMETER;
}
FreePool (StrTemp);
}
}
}
return EFI_SUCCESS;
}