/**
  Convert the IFR data into the network configuration data and set the IP
  configure parameters for the NIC.

  @param[in]       IfrFormNvData     The IFR NV data.
  @param[in, out]  Instance          The IP4 config2 instance.

  @retval EFI_SUCCESS            The configure parameter for this NIC was
                                 set successfully.
  @retval EFI_INVALID_PARAMETER  The address information for setting is invalid.
  @retval Others                 Other errors as indicated.

**/
EFI_STATUS
Ip4Config2ConvertIfrNvDataToConfigNvData (
  IN     IP4_CONFIG2_IFR_NVDATA     *IfrFormNvData,
  IN OUT IP4_CONFIG2_INSTANCE       *Instance
  )
{
  EFI_STATUS                       Status;
  EFI_IP4_CONFIG2_PROTOCOL         *Ip4Cfg2;
  IP4_CONFIG2_NVDATA               *Ip4NvData;

  EFI_IP_ADDRESS                   StationAddress;
  EFI_IP_ADDRESS                   SubnetMask;
  EFI_IP_ADDRESS                   Gateway;
  IP4_ADDR                         Ip;
  EFI_IPv4_ADDRESS                 *DnsAddress;
  UINTN                            DnsCount;
  UINTN                            Index;

  EFI_EVENT                        TimeoutEvent;
  EFI_EVENT                        SetAddressEvent;
  BOOLEAN                          IsAddressOk;
  UINTN                            DataSize;
  EFI_INPUT_KEY                    Key;

  Status          = EFI_SUCCESS;
  Ip4Cfg2         = &Instance->Ip4Config2;
  Ip4NvData       = &Instance->Ip4NvData;

  DnsCount        = 0;
  DnsAddress      = NULL;

  TimeoutEvent    = NULL;
  SetAddressEvent = NULL;



  if (Instance == NULL || IfrFormNvData == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (IfrFormNvData->Configure != TRUE) {
    return EFI_SUCCESS;
  }

  if (IfrFormNvData->DhcpEnable == TRUE) {
    Ip4NvData->Policy = Ip4Config2PolicyDhcp;

    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypePolicy,
                        sizeof (EFI_IP4_CONFIG2_POLICY),
                        &Ip4NvData->Policy
                        );
    if (EFI_ERROR(Status)) {
      return Status;
    }
  } else {
    //
    // Get Ip4NvData from IfrFormNvData if it is valid.
    //
    Ip4NvData->Policy = Ip4Config2PolicyStatic;

    Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
    if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
      return EFI_INVALID_PARAMETER;
    }

    Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
    if (EFI_ERROR (Status) ||
        (SubnetMask.Addr[0] != 0 && !NetIp4IsUnicast (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) ||
        !Ip4StationAddressValid (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
      return EFI_INVALID_PARAMETER;
    }

    Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
    if (EFI_ERROR (Status) ||
        (Gateway.Addr[0] != 0 && SubnetMask.Addr[0] != 0 && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (SubnetMask.Addr[0])))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
      return EFI_INVALID_PARAMETER;
    }

    Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
    if (!EFI_ERROR (Status) && DnsCount > 0) {
      for (Index = 0; Index < DnsCount; Index ++) {
        CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
        if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
          CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
          FreePool(DnsAddress);
          return EFI_INVALID_PARAMETER;
        }
      }
    } else {
      if (EFI_ERROR (Status)) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
      }
    }

    if (Ip4NvData->ManualAddress != NULL) {
      FreePool(Ip4NvData->ManualAddress);
    }
    Ip4NvData->ManualAddressCount = 1;
    Ip4NvData->ManualAddress = AllocateZeroPool(sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS));
    if (Ip4NvData->ManualAddress == NULL) {
      if (DnsAddress != NULL) {
        FreePool(DnsAddress);
      }

      return EFI_OUT_OF_RESOURCES;
    }
    CopyMem(&Ip4NvData->ManualAddress->Address, &StationAddress.v4, sizeof(EFI_IPv4_ADDRESS));
    CopyMem(&Ip4NvData->ManualAddress->SubnetMask, &SubnetMask.v4, sizeof(EFI_IPv4_ADDRESS));

    if (Ip4NvData->GatewayAddress != NULL) {
      FreePool(Ip4NvData->GatewayAddress);
    }
    Ip4NvData->GatewayAddressCount = 1;
    Ip4NvData->GatewayAddress = AllocateZeroPool(sizeof(EFI_IPv4_ADDRESS));
    if (Ip4NvData->GatewayAddress == NULL) {
      if (DnsAddress != NULL) {
        FreePool(DnsAddress);
      }
      return EFI_OUT_OF_RESOURCES;
    }
    CopyMem(Ip4NvData->GatewayAddress, &Gateway.v4, sizeof(EFI_IPv4_ADDRESS));

    if (Ip4NvData->DnsAddress != NULL) {
      FreePool(Ip4NvData->DnsAddress);
    }
    Ip4NvData->DnsAddressCount = (UINT32) DnsCount;
    Ip4NvData->DnsAddress      = DnsAddress;

    //
    // Setting Ip4NvData.
    //
    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypePolicy,
                        sizeof (EFI_IP4_CONFIG2_POLICY),
                        &Ip4NvData->Policy
                        );
    if (EFI_ERROR(Status)) {
      return Status;
    }

    //
    // Create events & timers for asynchronous settings.
    //
    Status = gBS->CreateEvent (
                    EVT_TIMER,
                    TPL_CALLBACK,
                    NULL,
                    NULL,
                    &TimeoutEvent
                    );
    if (EFI_ERROR (Status)) {
      return EFI_OUT_OF_RESOURCES;
    }

    Status = gBS->CreateEvent (
                    EVT_NOTIFY_SIGNAL,
                    TPL_NOTIFY,
                    Ip4Config2ManualAddressNotify,
                    &IsAddressOk,
                    &SetAddressEvent
                    );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    IsAddressOk = FALSE;

    Status = Ip4Cfg2->RegisterDataNotify (
                        Ip4Cfg2,
                        Ip4Config2DataTypeManualAddress,
                        SetAddressEvent
                        );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    //
    // Set ManualAddress.
    //
    DataSize = Ip4NvData->ManualAddressCount * sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS);
    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypeManualAddress,
                        DataSize,
                        (VOID *) Ip4NvData->ManualAddress
                        );

    if (Status == EFI_NOT_READY) {
      gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);
      while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
        if (IsAddressOk) {
          Status = EFI_SUCCESS;
          break;
        }
      }
    }

    Ip4Cfg2->UnregisterDataNotify (
               Ip4Cfg2,
               Ip4Config2DataTypeManualAddress,
               SetAddressEvent
               );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    //
    // Set gateway.
    //
    DataSize = Ip4NvData->GatewayAddressCount * sizeof (EFI_IPv4_ADDRESS);
    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypeGateway,
                        DataSize,
                        Ip4NvData->GatewayAddress
                        );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    //
    // Set DNS addresses.
    //
    if (Ip4NvData->DnsAddressCount > 0 && Ip4NvData->DnsAddress != NULL) {
      DataSize = Ip4NvData->DnsAddressCount * sizeof (EFI_IPv4_ADDRESS);
      Status = Ip4Cfg2->SetData (
                          Ip4Cfg2,
                          Ip4Config2DataTypeDnsServer,
                          DataSize,
                          Ip4NvData->DnsAddress
                          );

      if (EFI_ERROR (Status)) {
        goto Exit;
      }
    }
  }

Exit:
  if (SetAddressEvent != NULL) {
    gBS->CloseEvent (SetAddressEvent);
  }

  if (TimeoutEvent != NULL) {
    gBS->CloseEvent (TimeoutEvent);
  }

  return Status;
}
Exemple #2
0
/**
  This function is called to provide results data to the driver.
  This data consists of a unique key that is used to identify
  which data is either being passed back or being asked for.

  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
  @param[in]  Action             Specifies the type of action taken by the browser.
  @param[in]  QuestionId         A unique value which is sent to the original
                                 exporting driver so that it can identify the type
                                 of data to expect. The format of the data tends to
                                 vary based on the opcode that enerated the callback.
  @param[in]  Type               The type of value for the question.
  @param[in]  Value              A pointer to the data being sent to the original
                                 exporting driver.
  @param[out]  ActionRequest     On return, points to the action requested by the
                                 callback function.

  @retval EFI_SUCCESS            The callback successfully handled the action.
  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
                                 variable and its data.
  @retval EFI_DEVICE_ERROR       The variable could not be saved.
  @retval EFI_UNSUPPORTED        The specified Action is not supported by the
                                 callback.Currently not implemented.
  @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
  @retval Others                 Other errors as indicated.
**/
EFI_STATUS
EFIAPI
Ip4FormCallback (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
  IN  EFI_BROWSER_ACTION                     Action,
  IN  EFI_QUESTION_ID                        QuestionId,
  IN  UINT8                                  Type,
  IN  EFI_IFR_TYPE_VALUE                     *Value,
  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
  )
{
  IP4_CONFIG_INSTANCE       *Ip4ConfigInstance;
  CHAR8                     Ip4String[IP4_STR_MAX_SIZE];
  IP4_CONFIG_IFR_NVDATA     *IfrFormNvData;
  EFI_IP_ADDRESS            HostIp;
  EFI_IP_ADDRESS            SubnetMask;
  EFI_IP_ADDRESS            Gateway;
  EFI_STATUS                Status;
  EFI_INPUT_KEY             Key;

  Ip4ConfigInstance = IP4_CONFIG_INSTANCE_FROM_CONFIG_ACCESS (This);

  IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG_IFR_NVDATA));
  if (IfrFormNvData == NULL) {
    return EFI_OUT_OF_RESOURCES;
  }

  //
  // Retrive uncommitted data from Browser
  //
  if (!HiiGetBrowserData (&mNicIp4ConfigNvDataGuid, EFI_NIC_IP4_CONFIG_VARIABLE, sizeof (IP4_CONFIG_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {
    FreePool (IfrFormNvData);
    return EFI_NOT_FOUND;
  }

  Status = EFI_SUCCESS;

  switch (QuestionId) {

  case KEY_ENABLE:
    if (IfrFormNvData->Configure == 0) {
      Ip4ConfigInstance->Ip4ConfigCallbackInfo.Configured = FALSE;
    } else {
      Ip4ConfigInstance->Ip4ConfigCallbackInfo.Configured = TRUE;
    }
    break;

  case KEY_DHCP_ENABLE:
    if (IfrFormNvData->DhcpEnable == 0) {
      Ip4ConfigInstance->Ip4ConfigCallbackInfo.DhcpEnabled = FALSE;
    } else {
      Ip4ConfigInstance->Ip4ConfigCallbackInfo.DhcpEnabled = TRUE;
    }

    break;

  case KEY_LOCAL_IP:
    UnicodeStrToAsciiStr (IfrFormNvData->StationAddress, Ip4String);
    Status = Ip4AsciiStrToIp (Ip4String, &HostIp.v4);
    if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
      Status = EFI_INVALID_PARAMETER;
    } else {
      CopyMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
    }

    break;

  case KEY_SUBNET_MASK:
    UnicodeStrToAsciiStr (IfrFormNvData->SubnetMask, Ip4String);
    Status = Ip4AsciiStrToIp (Ip4String, &SubnetMask.v4);
    if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid SubnetMask!", NULL);
      Status = EFI_INVALID_PARAMETER;
    } else {
      CopyMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
    }

    break;

  case KEY_GATE_WAY:
    UnicodeStrToAsciiStr (IfrFormNvData->GatewayAddress, Ip4String);
    Status = Ip4AsciiStrToIp (Ip4String, &Gateway.v4);
    if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
      Status = EFI_INVALID_PARAMETER;
    } else {
      CopyMem (&Ip4ConfigInstance->Ip4ConfigCallbackInfo.Gateway, &Gateway.v4, sizeof (Gateway.v4));
    }

    break;

  case KEY_SAVE_CHANGES:

    Status = Ip4ConfigConvertIfrNvDataToDeviceConfigData (Ip4ConfigInstance);

    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;

    break;

  default:

    break;
  }

  if (!EFI_ERROR (Status)) {
    //
    // Pass changed uncommitted data back to Form Browser
    //
    HiiSetBrowserData (&gEfiNicIp4ConfigVariableGuid, EFI_NIC_IP4_CONFIG_VARIABLE, sizeof (IP4_CONFIG_IFR_NVDATA), (UINT8 *) IfrFormNvData, NULL);
  }

  FreePool (IfrFormNvData);

  return Status;
}
/**
  This function is called to provide results data to the driver.
  This data consists of a unique key that is used to identify
  which data is either being passed back or being asked for.

  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
  @param[in]  Action             Specifies the type of action taken by the browser.
  @param[in]  QuestionId         A unique value which is sent to the original
                                 exporting driver so that it can identify the type
                                 of data to expect. The format of the data tends to
                                 vary based on the opcode that enerated the callback.
  @param[in]  Type               The type of value for the question.
  @param[in]  Value              A pointer to the data being sent to the original
                                 exporting driver.
  @param[out] ActionRequest      On return, points to the action requested by the
                                 callback function.

  @retval EFI_SUCCESS            The callback successfully handled the action.
  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
                                 variable and its data.
  @retval EFI_DEVICE_ERROR       The variable could not be saved.
  @retval EFI_UNSUPPORTED        The specified Action is not supported by the
                                 callback.Currently not implemented.
  @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
  @retval Others                 Other errors as indicated.

**/
EFI_STATUS
EFIAPI
Ip4FormCallback (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
  IN  EFI_BROWSER_ACTION                     Action,
  IN  EFI_QUESTION_ID                        QuestionId,
  IN  UINT8                                  Type,
  IN  EFI_IFR_TYPE_VALUE                     *Value,
  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
  )
{
  EFI_STATUS                Status;
  IP4_CONFIG2_INSTANCE      *Instance;
  IP4_CONFIG2_IFR_NVDATA    *IfrFormNvData;
  IP4_FORM_CALLBACK_INFO    *Private;

  EFI_IP_ADDRESS            StationAddress;
  EFI_IP_ADDRESS            SubnetMask;
  EFI_IP_ADDRESS            Gateway;
  IP4_ADDR                  Ip;
  EFI_IPv4_ADDRESS          *DnsAddress;
  UINTN                     DnsCount;
  UINTN                     Index;
  EFI_INPUT_KEY             Key;

  IfrFormNvData = NULL;
  DnsCount      = 0;
  DnsAddress    = NULL;

  if (Action == EFI_BROWSER_ACTION_CHANGED) {
    Private = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
    Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);

    IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
    if (IfrFormNvData == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }

    //
    // Retrieve uncommitted data from Browser
    //
    if (!HiiGetBrowserData (&gIp4Config2NvDataGuid, mIp4Config2StorageName, sizeof (IP4_CONFIG2_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {
      FreePool (IfrFormNvData);
      return EFI_NOT_FOUND;
    }

    Status = EFI_SUCCESS;

    switch (QuestionId) {
    case KEY_LOCAL_IP:
      Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
      if (EFI_ERROR (Status) || IP4_IS_UNSPECIFIED (NTOHL (StationAddress.Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (StationAddress.Addr[0]))) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
        Status = EFI_INVALID_PARAMETER;
      }
      break;

    case KEY_SUBNET_MASK:
      Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
      if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
        Status = EFI_INVALID_PARAMETER;
      }
      break;

    case KEY_GATE_WAY:
      Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
      if (EFI_ERROR (Status) || IP4_IS_LOCAL_BROADCAST(NTOHL(Gateway.Addr[0]))) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
        Status = EFI_INVALID_PARAMETER;
      }
      break;

    case KEY_DNS:
      Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
      if (!EFI_ERROR (Status) && DnsCount > 0) {
        for (Index = 0; Index < DnsCount; Index ++) {
          CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
          if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
            CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
            Status = EFI_INVALID_PARAMETER;
            break;
          }
        }
      } else {
        if (EFI_ERROR (Status)) {
          CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
        }
      }

      if(DnsAddress != NULL) {
        FreePool(DnsAddress);
      }
      break;

    case KEY_SAVE_CHANGES:
      Status = Ip4Config2ConvertIfrNvDataToConfigNvData (IfrFormNvData, Instance);
      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
      break;

    default:
      break;
    }

    FreePool (IfrFormNvData);

    return Status;
  }

  //
  // All other action return unsupported.
  //
  return EFI_UNSUPPORTED;
}