mirror of https://github.com/acidanthera/audk.git
409 lines
10 KiB
C
409 lines
10 KiB
C
/*++
|
|
|
|
Copyright (c) 2006, 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"
|
|
|
|
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
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
|
|
)
|
|
/*++
|
|
Routine Description:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
-2 = ignore, stop waiting
|
|
-1 = ignore, keep waiting
|
|
0 = accept, keep waiting
|
|
1 = accept, stop waiting
|
|
--*/
|
|
{
|
|
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 */
|