git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7290 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			395 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			395 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Routines used to operate the Ip4 configure variable.
 | 
						|
 | 
						|
Copyright (c) 2006 - 2008, Intel Corporation.<BR>                                                         
 | 
						|
All rights reserved. This program and the accompanying materials
 | 
						|
are licensed and made available under the terms and conditions of the BSD License
 | 
						|
which accompanies this distribution.  The full text of the license may be found at<BR>
 | 
						|
http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "NicIp4Variable.h"
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Check whether the configure parameter is valid.
 | 
						|
 | 
						|
  @param  NicConfig    The configure parameter to check
 | 
						|
 | 
						|
  @return TRUE if the parameter is valid for the interface, otherwise FALSE.
 | 
						|
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
Ip4ConfigIsValid (
 | 
						|
  IN NIC_IP4_CONFIG_INFO    *NicConfig
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_IP4_IPCONFIG_DATA     *IpConfig;
 | 
						|
  IP4_ADDR                  Station;
 | 
						|
  IP4_ADDR                  Netmask;
 | 
						|
  IP4_ADDR                  Gateway;
 | 
						|
  UINT32                    Index;
 | 
						|
 | 
						|
  IpConfig = &NicConfig->Ip4Info;
 | 
						|
 | 
						|
  if (NicConfig->Source == IP4_CONFIG_SOURCE_STATIC) {
 | 
						|
    //
 | 
						|
    // Validate that the addresses are unicast and mask
 | 
						|
    // is properly formated
 | 
						|
    //
 | 
						|
    Station = EFI_NTOHL (IpConfig->StationAddress);
 | 
						|
    Netmask = EFI_NTOHL (IpConfig->SubnetMask);
 | 
						|
 | 
						|
    if ((Netmask == 0) || !IP4_IS_VALID_NETMASK (Netmask) ||
 | 
						|
        (Station == 0) || !Ip4IsUnicast (Station, Netmask)) {
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Validate that the next hops are on the connected network
 | 
						|
    // or that is a direct route (Gateway == 0).
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < IpConfig->RouteTableSize; Index++) {
 | 
						|
      Gateway = EFI_NTOHL (IpConfig->RouteTable[Index].GatewayAddress);
 | 
						|
 | 
						|
      if ((Gateway != 0) && (!IP4_NET_EQUAL (Station, Gateway, Netmask) ||
 | 
						|
          !Ip4IsUnicast (Gateway, Netmask))) {
 | 
						|
        return FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    return TRUE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // return false if it is an unkown configure source. Valid
 | 
						|
  // sources are static and dhcp.
 | 
						|
  //
 | 
						|
  return (BOOLEAN) (NicConfig->Source == IP4_CONFIG_SOURCE_DHCP);
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Read the ip4 configure variable from the EFI variable.
 | 
						|
 | 
						|
  None
 | 
						|
 | 
						|
  @return The IP4 configure read if it is there and is valid, otherwise NULL
 | 
						|
 | 
						|
**/
 | 
						|
IP4_CONFIG_VARIABLE *
 | 
						|
Ip4ConfigReadVariable (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  IP4_CONFIG_VARIABLE       *Variable;
 | 
						|
  EFI_STATUS                Status;
 | 
						|
  UINTN                     Size;
 | 
						|
  UINT16                    CheckSum;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get the size of variable, then allocate a buffer to read the variable.
 | 
						|
  //
 | 
						|
  Size     = 0;
 | 
						|
  Variable = NULL;
 | 
						|
  Status   = gRT->GetVariable (
 | 
						|
                    EFI_NIC_IP4_CONFIG_VARIABLE,
 | 
						|
                    &gEfiNicIp4ConfigVariableGuid,
 | 
						|
                    NULL,
 | 
						|
                    &Size,
 | 
						|
                    NULL
 | 
						|
                    );
 | 
						|
 | 
						|
  if (Status != EFI_BUFFER_TOO_SMALL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Size < sizeof (IP4_CONFIG_VARIABLE)) {
 | 
						|
    goto REMOVE_VARIABLE;
 | 
						|
  }
 | 
						|
 | 
						|
  Variable = AllocatePool (Size);
 | 
						|
 | 
						|
  if (Variable == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = gRT->GetVariable (
 | 
						|
                  EFI_NIC_IP4_CONFIG_VARIABLE,
 | 
						|
                  &gEfiNicIp4ConfigVariableGuid,
 | 
						|
                  NULL,
 | 
						|
                  &Size,
 | 
						|
                  Variable
 | 
						|
                  );
 | 
						|
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    goto ON_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Verify the checksum, variable size and count
 | 
						|
  //
 | 
						|
  CheckSum = (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32)Size));
 | 
						|
 | 
						|
  if ((CheckSum != 0) || (Size != Variable->Len)) {
 | 
						|
    goto REMOVE_VARIABLE;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((Variable->Count < 1) || (Variable->Count > MAX_IP4_CONFIG_IN_VARIABLE)) {
 | 
						|
    goto REMOVE_VARIABLE;
 | 
						|
  }
 | 
						|
 | 
						|
  return Variable;
 | 
						|
 | 
						|
REMOVE_VARIABLE:
 | 
						|
  Ip4ConfigWriteVariable (NULL);
 | 
						|
 | 
						|
ON_ERROR:
 | 
						|
  if (Variable != NULL) {
 | 
						|
    gBS->FreePool (Variable);
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Write the IP4 configure variable to the NVRAM. If Config
 | 
						|
  is NULL, remove the variable.
 | 
						|
 | 
						|
  @param  Config       The IP4 configure data to write
 | 
						|
 | 
						|
  @retval EFI_SUCCESS  The variable is written to the NVRam
 | 
						|
  @retval Others       Failed to write the variable.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
Ip4ConfigWriteVariable (
 | 
						|
  IN IP4_CONFIG_VARIABLE    *Config        OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                Status;
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
                  EFI_NIC_IP4_CONFIG_VARIABLE,
 | 
						|
                  &gEfiNicIp4ConfigVariableGuid,
 | 
						|
                  IP4_CONFIG_VARIABLE_ATTRIBUTES,
 | 
						|
                  (Config == NULL) ? 0 : Config->Len,
 | 
						|
                  Config
 | 
						|
                  );
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Locate the IP4 configure parameters from the variable.If a
 | 
						|
  configuration is found, copy it to a newly allocated block
 | 
						|
  of memory to avoid the alignment problem. Caller should
 | 
						|
  release the memory after use.
 | 
						|
 | 
						|
  @param  Variable     The IP4 configure variable to search in
 | 
						|
  @param  NicAddr      The interface address to check
 | 
						|
 | 
						|
  @return The point to the NIC's IP4 configure info if it is found
 | 
						|
          in the IP4 variable, otherwise NULL.
 | 
						|
 | 
						|
**/
 | 
						|
NIC_IP4_CONFIG_INFO *
 | 
						|
Ip4ConfigFindNicVariable (
 | 
						|
  IN IP4_CONFIG_VARIABLE    *Variable,
 | 
						|
  IN NIC_ADDR               *NicAddr
 | 
						|
  )
 | 
						|
{
 | 
						|
  NIC_IP4_CONFIG_INFO       Temp;
 | 
						|
  NIC_IP4_CONFIG_INFO       *Config;
 | 
						|
  UINT32                    Index;
 | 
						|
  UINT8                     *Cur;
 | 
						|
  UINT32                    Len;
 | 
						|
 | 
						|
  Cur = (UINT8*)&Variable->ConfigInfo;
 | 
						|
 | 
						|
  for (Index = 0; Index < Variable->Count; Index++) {
 | 
						|
    //
 | 
						|
    // Copy the data to Temp to avoid the alignment problems
 | 
						|
    //
 | 
						|
    CopyMem (&Temp, Cur, sizeof (NIC_IP4_CONFIG_INFO));
 | 
						|
    Len = SIZEOF_NIC_IP4_CONFIG_INFO (&Temp);
 | 
						|
 | 
						|
    //
 | 
						|
    // Found the matching configuration parameters, allocate
 | 
						|
    // a block of memory then copy it out.
 | 
						|
    //
 | 
						|
    if (NIC_ADDR_EQUAL (&Temp.NicAddr, NicAddr)) {
 | 
						|
      Config = AllocatePool (Len);
 | 
						|
 | 
						|
      if (Config == NULL) {
 | 
						|
        return NULL;
 | 
						|
      }
 | 
						|
 | 
						|
      CopyMem (Config, Cur, Len);
 | 
						|
      Ip4ConfigFixRouteTablePointer (&Config->Ip4Info);
 | 
						|
      return Config;
 | 
						|
    }
 | 
						|
 | 
						|
    Cur += Len;
 | 
						|
  }
 | 
						|
 | 
						|
  return NULL;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Modify the configuration parameter for the NIC in the variable.
 | 
						|
  If Config is NULL, old configuration will be remove from the new
 | 
						|
  variable. Otherwise, append it or replace the old one.
 | 
						|
 | 
						|
  @param  Variable     The IP4 variable to change
 | 
						|
  @param  NicAddr      The interface to search
 | 
						|
  @param  Config       The new configuration parameter (NULL to remove the old)
 | 
						|
 | 
						|
  @return The new IP4_CONFIG_VARIABLE variable if the new variable has at
 | 
						|
          least one NIC configure and no EFI_OUT_OF_RESOURCES failure.
 | 
						|
          Return NULL either because failed to locate memory for new variable
 | 
						|
          or the only NIC configure is removed from the Variable.
 | 
						|
 | 
						|
**/
 | 
						|
IP4_CONFIG_VARIABLE *
 | 
						|
Ip4ConfigModifyVariable (
 | 
						|
  IN IP4_CONFIG_VARIABLE    *Variable     OPTIONAL,
 | 
						|
  IN NIC_ADDR               *NicAddr,
 | 
						|
  IN NIC_IP4_CONFIG_INFO    *Config       OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  NIC_IP4_CONFIG_INFO       Temp;
 | 
						|
  NIC_IP4_CONFIG_INFO       *Old;
 | 
						|
  IP4_CONFIG_VARIABLE       *NewVar;
 | 
						|
  UINT32                    Len;
 | 
						|
  UINT32                    TotalLen;
 | 
						|
  UINT32                    Count;
 | 
						|
  UINT8                     *Next;
 | 
						|
  UINT8                     *Cur;
 | 
						|
  UINT32                    Index;
 | 
						|
 | 
						|
  ASSERT ((Variable != NULL) || (Config != NULL));
 | 
						|
 | 
						|
  //
 | 
						|
  // Compute the total length
 | 
						|
  //
 | 
						|
  if (Variable != NULL) {
 | 
						|
    //
 | 
						|
    // Variable != NULL, then Config can be NULL or not.  and so is
 | 
						|
    // the Old. If old configure exists, it is removed from the
 | 
						|
    // Variable. New configure is append to the variable.
 | 
						|
    //
 | 
						|
    //
 | 
						|
    Count     = Variable->Count;
 | 
						|
    Cur       = (UINT8 *)&Variable->ConfigInfo;
 | 
						|
    TotalLen  = Variable->Len;
 | 
						|
 | 
						|
    Old       = Ip4ConfigFindNicVariable (Variable, NicAddr);
 | 
						|
 | 
						|
    if (Old != NULL) {
 | 
						|
      TotalLen -= SIZEOF_NIC_IP4_CONFIG_INFO (Old);
 | 
						|
      gBS->FreePool (Old);
 | 
						|
    }
 | 
						|
 | 
						|
    if (Config != NULL) {
 | 
						|
      TotalLen += SIZEOF_NIC_IP4_CONFIG_INFO (Config);
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Return NULL if the only NIC_IP4_CONFIG_INFO is being removed.
 | 
						|
    //
 | 
						|
    if (TotalLen < sizeof (IP4_CONFIG_VARIABLE)) {
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
 | 
						|
  } else {
 | 
						|
    //
 | 
						|
    // Variable == NULL and Config != NULL, Create a new variable with
 | 
						|
    // this NIC configure.
 | 
						|
    //
 | 
						|
    Count     = 0;
 | 
						|
    Cur       = NULL;
 | 
						|
    TotalLen  = sizeof (IP4_CONFIG_VARIABLE) - sizeof (NIC_IP4_CONFIG_INFO)
 | 
						|
                + SIZEOF_NIC_IP4_CONFIG_INFO (Config);
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (TotalLen >= sizeof (IP4_CONFIG_VARIABLE));
 | 
						|
 | 
						|
  NewVar = AllocateZeroPool (TotalLen);
 | 
						|
 | 
						|
  if (NewVar == NULL) {
 | 
						|
    return NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  NewVar->Len = TotalLen;
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the other configure parameters from the old variable
 | 
						|
  //
 | 
						|
  Next = (UINT8 *)&NewVar->ConfigInfo;
 | 
						|
 | 
						|
  for (Index = 0; Index < Count; Index++) {
 | 
						|
    CopyMem (&Temp, Cur, sizeof (NIC_IP4_CONFIG_INFO));
 | 
						|
    Len = SIZEOF_NIC_IP4_CONFIG_INFO (&Temp);
 | 
						|
 | 
						|
    if (!NIC_ADDR_EQUAL (&Temp.NicAddr, NicAddr)) {
 | 
						|
      CopyMem (Next, Cur, Len);
 | 
						|
      Next += Len;
 | 
						|
      NewVar->Count++;
 | 
						|
    }
 | 
						|
 | 
						|
    Cur += Len;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Append the new configure if it isn't NULL.
 | 
						|
  //
 | 
						|
  Len = 0;
 | 
						|
 | 
						|
  if (Config != NULL) {
 | 
						|
    Len = SIZEOF_NIC_IP4_CONFIG_INFO (Config);
 | 
						|
 | 
						|
    CopyMem (Next, Config, Len);
 | 
						|
    NewVar->Count++;
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (Next + Len == (UINT8 *) NewVar + TotalLen);
 | 
						|
 | 
						|
  NewVar->CheckSum = (UINT16) (~NetblockChecksum ((UINT8 *) NewVar, TotalLen));
 | 
						|
  return NewVar;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fix the RouteTable pointer in an EFI_IP4_IPCONFIG_DATA structure. 
 | 
						|
  
 | 
						|
  The pointer is set to be immediately follow the ConfigData if there're entries
 | 
						|
  in the RouteTable. Otherwise it is set to NULL.
 | 
						|
  
 | 
						|
  @param  ConfigData     The IP4 IP configure data.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
Ip4ConfigFixRouteTablePointer (
 | 
						|
  IN OUT EFI_IP4_IPCONFIG_DATA  *ConfigData
 | 
						|
  )
 | 
						|
{
 | 
						|
  //
 | 
						|
  // The memory used for route table entries must immediately follow 
 | 
						|
  // the ConfigData and be not packed.
 | 
						|
  //
 | 
						|
  if (ConfigData->RouteTableSize > 0) {
 | 
						|
    ConfigData->RouteTable = (EFI_IP4_ROUTE_TABLE *) (ConfigData + 1);
 | 
						|
  } else {
 | 
						|
    ConfigData->RouteTable = NULL;
 | 
						|
  }
 | 
						|
}
 | 
						|
 |