/*++ | |
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: | |
PxeDhcp4Release.c | |
Abstract: | |
Transmit release packet, free allocations and shutdown PxeDhcp4. | |
--*/ | |
#include "PxeDhcp4.h" | |
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ | |
EFI_STATUS | |
EFIAPI | |
PxeDhcp4Release ( | |
IN EFI_PXE_DHCP4_PROTOCOL *This | |
) | |
{ | |
PXE_DHCP4_PRIVATE_DATA *Private; | |
EFI_IP_ADDRESS ServerIp; | |
EFI_IP_ADDRESS client_ip; | |
EFI_IP_ADDRESS gateway_ip; | |
EFI_IP_ADDRESS subnet_mask; | |
EFI_STATUS efi_status; | |
DHCP4_OP *op; | |
UINT8 op_list[20]; | |
// | |
// Check for invalid parameters. | |
// | |
if (This == NULL) { | |
return EFI_INVALID_PARAMETER; | |
} | |
// | |
// Release does nothing if the protocol has never been setup. | |
// | |
if (This->Data == NULL) { | |
return EFI_NOT_STARTED; | |
} | |
// | |
// Fail if we do not have valid 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; | |
} | |
// | |
// If this is a BOOTP session and there is not a DHCP Ack | |
// packet, just release storage and return. | |
// | |
if (This->Data->IsBootp || !This->Data->IsAck) { | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return EFI_SUCCESS; | |
} | |
// | |
// Build option list for DHCP Release packet. | |
// If any errors occur, just release storage and return. | |
// | |
// | |
// Message type is first. | |
// | |
op_list[0] = DHCP4_MESSAGE_TYPE; | |
op_list[1] = 1; | |
op_list[2] = DHCP4_MESSAGE_TYPE_RELEASE; | |
// | |
// Followed by server identifier. | |
// | |
efi_status = find_opt ( | |
&This->Data->Request, | |
DHCP4_SERVER_IDENTIFIER, | |
0, | |
&op | |
); | |
if (EFI_ERROR (efi_status)) { | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return EFI_SUCCESS; | |
} | |
if (op->len != 4) { | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return EFI_SUCCESS; | |
} | |
CopyMem (&ServerIp, op->data, 4); | |
op_list[3] = DHCP4_SERVER_IDENTIFIER; | |
op_list[4] = 4; | |
CopyMem (&op_list[5], &ServerIp, 4); | |
// | |
// Followed by end. | |
// | |
op_list[9] = DHCP4_END; | |
// | |
// We need a subnet mask for IP stack operation. | |
// | |
efi_status = find_opt ( | |
&This->Data->AckNak, | |
DHCP4_SUBNET_MASK, | |
0, | |
&op | |
); | |
if (EFI_ERROR (efi_status)) { | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return EFI_SUCCESS; | |
} | |
if (op->len != 4) { | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return EFI_SUCCESS; | |
} | |
ZeroMem (&subnet_mask, sizeof (EFI_IP_ADDRESS)); | |
CopyMem (&subnet_mask, op->data, 4); | |
// | |
// Gateway IP address may be needed. | |
// | |
ZeroMem (&gateway_ip, sizeof (EFI_IP_ADDRESS)); | |
CopyMem (&gateway_ip, &This->Data->AckNak.dhcp4.giaddr, 4); | |
// | |
// Client IP address needed for IP stack operation. | |
// | |
ZeroMem (&client_ip, sizeof (EFI_IP_ADDRESS)); | |
CopyMem (&client_ip, &This->Data->AckNak.dhcp4.yiaddr, 4); | |
// | |
// Enable UDP... | |
// | |
efi_status = start_udp (Private, &client_ip, &subnet_mask); | |
if (EFI_ERROR (efi_status)) { | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return efi_status; | |
} | |
// | |
// Gather information out of DHCP request packet needed for | |
// DHCP release packet. | |
// | |
// | |
// Setup DHCP Release packet. | |
// | |
CopyMem (&This->Data->Request.dhcp4.ciaddr, &client_ip, 4); | |
ZeroMem (&This->Data->Request.dhcp4.yiaddr, 12); | |
ZeroMem (&This->Data->Request.dhcp4.sname, 64 + 128); | |
This->Data->Request.dhcp4.hops = 0; | |
This->Data->Request.dhcp4.secs = 0; | |
This->Data->Request.dhcp4.flags = 0; | |
ZeroMem ( | |
&This->Data->Request.dhcp4.options, | |
sizeof This->Data->Request.dhcp4.options | |
); | |
CopyMem (&This->Data->Request.dhcp4.options, op_list, 10); | |
// | |
// Transmit DHCP Release packet. | |
// | |
tx_udp ( | |
Private, | |
&ServerIp, | |
&gateway_ip, | |
&client_ip, | |
&This->Data->Request, | |
DHCP4_MAX_PACKET_SIZE - (DHCP4_UDP_HEADER_SIZE + DHCP4_IP_HEADER_SIZE) | |
); | |
gBS->Stall (1000000); /* 1/10th second */ | |
// | |
// Shutdown PXE BaseCode and release local storage. | |
// | |
stop_udp (Private); | |
gBS->FreePool (This->Data); | |
This->Data = NULL; | |
if (Private->StopPxeBc) { | |
Private->PxeBc->Stop (Private->PxeBc); | |
} | |
return EFI_SUCCESS; | |
} | |
/* eof - PxeDhcp4Release.c */ |