mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 02:40:26 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@3492 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			409 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			409 lines
		
	
	
		
			9.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
 | 
						|
Copyright (c) 2004, Intel Corporation
 | 
						|
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
 | 
						|
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.
 | 
						|
 | 
						|
Module Name:
 | 
						|
  PxeDhcp4RenewRebind.c
 | 
						|
 | 
						|
Abstract:
 | 
						|
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
 | 
						|
#include "PxeDhcp4.h"
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
 | 
						|
/**
 | 
						|
  Parameters:
 | 
						|
 | 
						|
  @return -2 = ignore, stop waiting
 | 
						|
  @return -1 = ignore, keep waiting
 | 
						|
  @return 0 = accept, keep waiting
 | 
						|
  @return 1 = accept, stop waiting
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
INTN
 | 
						|
acknak_verify (
 | 
						|
  IN PXE_DHCP4_PRIVATE_DATA *Private,
 | 
						|
  IN DHCP4_PACKET           *tx_pkt,
 | 
						|
  IN DHCP4_PACKET           *rx_pkt,
 | 
						|
  IN UINTN                  rx_pkt_size
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  efi_status;
 | 
						|
  DHCP4_OP    *msg_type_op;
 | 
						|
  DHCP4_OP    *srvid_op;
 | 
						|
  DHCP4_OP    *renew_op;
 | 
						|
  DHCP4_OP    *rebind_op;
 | 
						|
  DHCP4_OP    *lease_time_op;
 | 
						|
  UINT32      magik;
 | 
						|
 | 
						|
  //
 | 
						|
  // Verify parameters.  Unused parameters are also touched
 | 
						|
  // to make the compiler happy.
 | 
						|
  //
 | 
						|
  ASSERT (Private);
 | 
						|
  ASSERT (rx_pkt);
 | 
						|
 | 
						|
  if (Private == NULL || rx_pkt == NULL) {
 | 
						|
    return -2;
 | 
						|
  }
 | 
						|
 | 
						|
  tx_pkt      = tx_pkt;
 | 
						|
  rx_pkt_size = rx_pkt_size;
 | 
						|
 | 
						|
  //
 | 
						|
  // This must be a DHCP Ack message.
 | 
						|
  //
 | 
						|
  magik = htonl (DHCP4_MAGIK_NUMBER);
 | 
						|
 | 
						|
  if (CompareMem (&rx_pkt->dhcp4.magik, &magik, 4)) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  efi_status = find_opt (rx_pkt, DHCP4_MESSAGE_TYPE, 0, &msg_type_op);
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (msg_type_op->len != 1) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (msg_type_op->data[0] != DHCP4_MESSAGE_TYPE_ACK) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // There must be a server identifier.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (rx_pkt, DHCP4_SERVER_IDENTIFIER, 0, &srvid_op);
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  if (srvid_op->len != 4) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // There should be a renewal time.
 | 
						|
  // If there is not, we will default to the 7/8 of the rebinding time.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (rx_pkt, DHCP4_RENEWAL_TIME, 0, &renew_op);
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    renew_op = NULL;
 | 
						|
  } else if (renew_op->len != 4) {
 | 
						|
    renew_op = NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // There should be a rebinding time.
 | 
						|
  // If there is not, we will default to 7/8 of the lease time.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (rx_pkt, DHCP4_REBINDING_TIME, 0, &rebind_op);
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    rebind_op = NULL;
 | 
						|
  } else if (rebind_op->len != 4) {
 | 
						|
    rebind_op = NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // There should be a lease time.
 | 
						|
  // If there is not, we will default to one week.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (rx_pkt, DHCP4_LEASE_TIME, 0, &lease_time_op);
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    lease_time_op = NULL;
 | 
						|
  } else if (lease_time_op->len != 4) {
 | 
						|
    lease_time_op = NULL;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Packet looks good.  Double check the renew, rebind and lease times.
 | 
						|
  //
 | 
						|
  CopyMem (&Private->ServerIp, srvid_op->data, 4);
 | 
						|
 | 
						|
  if (renew_op != NULL) {
 | 
						|
    CopyMem (&Private->RenewTime, renew_op->data, 4);
 | 
						|
    Private->RenewTime = htonl (Private->RenewTime);
 | 
						|
  } else {
 | 
						|
    Private->RenewTime = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (rebind_op != NULL) {
 | 
						|
    CopyMem (&Private->RebindTime, rebind_op->data, 4);
 | 
						|
    Private->RebindTime = htonl (Private->RebindTime);
 | 
						|
  } else {
 | 
						|
    Private->RebindTime = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (lease_time_op != NULL) {
 | 
						|
    CopyMem (&Private->LeaseTime, lease_time_op->data, 4);
 | 
						|
    Private->LeaseTime = htonl (Private->LeaseTime);
 | 
						|
  } else {
 | 
						|
    Private->LeaseTime = 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->LeaseTime < 60) {
 | 
						|
    Private->LeaseTime = 7 * 86400;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->RebindTime < 52 || Private->RebindTime >= Private->LeaseTime) {
 | 
						|
    Private->RebindTime = Private->LeaseTime / 2 + Private->LeaseTime / 4 + Private->LeaseTime / 8;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->RenewTime < 45 || Private->RenewTime >= Private->RebindTime) {
 | 
						|
    Private->RenewTime = Private->RebindTime / 2 + Private->RebindTime / 4 + Private->RebindTime / 8;
 | 
						|
  }
 | 
						|
 | 
						|
  return 1;
 | 
						|
}
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
renew_rebind (
 | 
						|
  IN EFI_PXE_DHCP4_PROTOCOL *This,
 | 
						|
  IN UINTN                  seconds_timeout,
 | 
						|
  IN BOOLEAN                renew
 | 
						|
  )
 | 
						|
{
 | 
						|
  PXE_DHCP4_PRIVATE_DATA  *Private;
 | 
						|
  EFI_IP_ADDRESS          ServerIp;
 | 
						|
  EFI_IP_ADDRESS          client_ip;
 | 
						|
  EFI_IP_ADDRESS          subnet_mask;
 | 
						|
  EFI_IP_ADDRESS          gateway_ip;
 | 
						|
  DHCP4_PACKET            Request;
 | 
						|
  DHCP4_PACKET            AckNak;
 | 
						|
  DHCP4_OP                *op;
 | 
						|
  EFI_STATUS              efi_status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check for invalid parameters.
 | 
						|
  //
 | 
						|
  if (This == NULL || seconds_timeout < DHCP4_MIN_SECONDS || seconds_timeout > DHCP4_MAX_SECONDS) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Check for proper protocol state.
 | 
						|
  //
 | 
						|
  if (This->Data == NULL) {
 | 
						|
    return EFI_NOT_STARTED;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!This->Data->SelectCompleted) {
 | 
						|
    return EFI_NOT_READY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (This->Data->IsBootp) {
 | 
						|
    return EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!This->Data->IsAck) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Get pointer to instance data.
 | 
						|
  //
 | 
						|
  Private = PXE_DHCP4_PRIVATE_DATA_FROM_THIS (This);
 | 
						|
 | 
						|
  if (Private == NULL) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Private->PxeBc == NULL) {
 | 
						|
    return EFI_DEVICE_ERROR;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Copy Discover packet to temporary request packet
 | 
						|
  // to be used for Renew/Rebind operation.
 | 
						|
  //
 | 
						|
  CopyMem (&Request, &This->Data->Discover, sizeof (DHCP4_PACKET));
 | 
						|
 | 
						|
  CopyMem (&Request.dhcp4.ciaddr, &This->Data->AckNak.dhcp4.yiaddr, 4);
 | 
						|
 | 
						|
  Request.dhcp4.flags = 0;  /* Reply does not need to be broadcast. */
 | 
						|
 | 
						|
  //
 | 
						|
  // Change message type from discover to request.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (&Request, DHCP4_MESSAGE_TYPE, 0, &op);
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (op->len != 1) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  op->data[0] = DHCP4_MESSAGE_TYPE_REQUEST;
 | 
						|
 | 
						|
  //
 | 
						|
  // Need a subnet mask.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (
 | 
						|
                &This->Data->AckNak,
 | 
						|
                DHCP4_SUBNET_MASK,
 | 
						|
                0,
 | 
						|
                &op
 | 
						|
                );
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (op->len != 4) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS));
 | 
						|
  CopyMem (&subnet_mask, op->data, 4);
 | 
						|
 | 
						|
  //
 | 
						|
  // Need a server IP address (renew) or a broadcast
 | 
						|
  // IP address (rebind).
 | 
						|
  //
 | 
						|
  ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS));
 | 
						|
 | 
						|
  if (renew) {
 | 
						|
    efi_status = find_opt (
 | 
						|
                  &This->Data->AckNak,
 | 
						|
                  DHCP4_SERVER_IDENTIFIER,
 | 
						|
                  0,
 | 
						|
                  &op
 | 
						|
                  );
 | 
						|
 | 
						|
    if (EFI_ERROR (efi_status)) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    if (op->len != 4) {
 | 
						|
      return EFI_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
 | 
						|
    ZeroMem (&ServerIp, sizeof (EFI_IP_ADDRESS));
 | 
						|
    CopyMem (&ServerIp, op->data, 4);
 | 
						|
 | 
						|
    //
 | 
						|
    //
 | 
						|
    //
 | 
						|
    if (CompareMem (&This->Data->AckNak.dhcp4.giaddr, &gateway_ip, 4)) {
 | 
						|
      CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    SetMem (&ServerIp, sizeof (EFI_IP_ADDRESS), 0xFF);
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Need a client IP address.
 | 
						|
  //
 | 
						|
  ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS));
 | 
						|
  CopyMem (&client_ip, &Request.dhcp4.ciaddr, 4);
 | 
						|
 | 
						|
  //
 | 
						|
  //
 | 
						|
  //
 | 
						|
  efi_status = gBS->HandleProtocol (
 | 
						|
                      Private->Handle,
 | 
						|
                      &gEfiPxeDhcp4CallbackProtocolGuid,
 | 
						|
                      (VOID *) &Private->callback
 | 
						|
                      );
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    Private->callback = NULL;
 | 
						|
  }
 | 
						|
 | 
						|
  Private->function = renew ? EFI_PXE_DHCP4_FUNCTION_RENEW : EFI_PXE_DHCP4_FUNCTION_REBIND;
 | 
						|
 | 
						|
  //
 | 
						|
  // Transimit DHCP request and wait for DHCP ack...
 | 
						|
  //
 | 
						|
  efi_status = tx_rx_udp (
 | 
						|
                Private,
 | 
						|
                &ServerIp,
 | 
						|
                &gateway_ip,
 | 
						|
                &client_ip,
 | 
						|
                &subnet_mask,
 | 
						|
                &Request,
 | 
						|
                &AckNak,
 | 
						|
                &acknak_verify,
 | 
						|
                seconds_timeout
 | 
						|
                );
 | 
						|
 | 
						|
  if (EFI_ERROR (efi_status)) {
 | 
						|
    Private->callback = NULL;
 | 
						|
    return efi_status;
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // Copy server identifier, renewal time and rebinding time
 | 
						|
  // from temporary ack/nak packet into cached ack/nak packet.
 | 
						|
  //
 | 
						|
  efi_status = find_opt (
 | 
						|
                &This->Data->AckNak,
 | 
						|
                DHCP4_SERVER_IDENTIFIER,
 | 
						|
                0,
 | 
						|
                &op
 | 
						|
                );
 | 
						|
 | 
						|
  if (!EFI_ERROR (efi_status)) {
 | 
						|
    if (op->len == 4) {
 | 
						|
      CopyMem (op->data, &Private->ServerIp, 4);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  efi_status = find_opt (&This->Data->AckNak, DHCP4_RENEWAL_TIME, 0, &op);
 | 
						|
 | 
						|
  if (!EFI_ERROR (efi_status)) {
 | 
						|
    if (op->len == 4) {
 | 
						|
      CopyMem (op->data, &Private->RenewTime, 4);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  efi_status = find_opt (&This->Data->AckNak, DHCP4_REBINDING_TIME, 0, &op);
 | 
						|
 | 
						|
  if (!EFI_ERROR (efi_status)) {
 | 
						|
    if (op->len == 4) {
 | 
						|
      CopyMem (op->data, &Private->RebindTime, 4);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  Private->callback = NULL;
 | 
						|
  return efi_status;
 | 
						|
}
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PxeDhcp4Renew (
 | 
						|
  IN EFI_PXE_DHCP4_PROTOCOL *This,
 | 
						|
  IN UINTN                  seconds_timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  return renew_rebind (This, seconds_timeout, TRUE);
 | 
						|
}
 | 
						|
 | 
						|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
PxeDhcp4Rebind (
 | 
						|
  IN EFI_PXE_DHCP4_PROTOCOL *This,
 | 
						|
  IN UINTN                  seconds_timeout
 | 
						|
  )
 | 
						|
{
 | 
						|
  return renew_rebind (This, seconds_timeout, FALSE);
 | 
						|
}
 | 
						|
 | 
						|
/* eof - PxeDhcp4RenewRebind.c */
 |