NetworkPkg: Add DNS feature support over IPv4 and IPv6.
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: jiaxinwu <jiaxin.wu@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17854 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
762
NetworkPkg/DnsDxe/DnsDhcp.c
Normal file
762
NetworkPkg/DnsDxe/DnsDhcp.c
Normal file
@@ -0,0 +1,762 @@
|
||||
/** @file
|
||||
Functions implementation related with DHCPv4/v6 for DNS driver.
|
||||
|
||||
Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
|
||||
This software and associated documentation (if any) is furnished
|
||||
under a license and may only be used or copied in accordance
|
||||
with the terms of the license. Except as permitted by such
|
||||
license, no part of this software or documentation may be
|
||||
reproduced, stored in a retrieval system, or transmitted in any
|
||||
form or by any means without the express written consent of
|
||||
Intel Corporation.
|
||||
|
||||
**/
|
||||
|
||||
#include "DnsImpl.h"
|
||||
|
||||
/**
|
||||
This function initialize the DHCP4 message instance.
|
||||
|
||||
This function will pad each item of dhcp4 message packet.
|
||||
|
||||
@param Seed Pointer to the message instance of the DHCP4 packet.
|
||||
@param InterfaceInfo Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.
|
||||
|
||||
**/
|
||||
VOID
|
||||
DnsInitSeedPacket (
|
||||
OUT EFI_DHCP4_PACKET *Seed,
|
||||
IN EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo
|
||||
)
|
||||
{
|
||||
EFI_DHCP4_HEADER *Header;
|
||||
|
||||
//
|
||||
// Get IfType and HwAddressSize from SNP mode data.
|
||||
//
|
||||
Seed->Size = sizeof (EFI_DHCP4_PACKET);
|
||||
Seed->Length = sizeof (Seed->Dhcp4);
|
||||
Header = &Seed->Dhcp4.Header;
|
||||
ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
|
||||
Header->OpCode = DHCP4_OPCODE_REQUEST;
|
||||
Header->HwType = InterfaceInfo->IfType;
|
||||
Header->HwAddrLen = (UINT8) InterfaceInfo->HwAddressSize;
|
||||
CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen);
|
||||
|
||||
Seed->Dhcp4.Magik = DHCP4_MAGIC;
|
||||
Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
|
||||
}
|
||||
|
||||
/**
|
||||
The common notify function.
|
||||
|
||||
@param[in] Event The event signaled.
|
||||
@param[in] Context The context.
|
||||
|
||||
**/
|
||||
VOID
|
||||
EFIAPI
|
||||
DhcpCommonNotify (
|
||||
IN EFI_EVENT Event,
|
||||
IN VOID *Context
|
||||
)
|
||||
{
|
||||
if ((Event == NULL) || (Context == NULL)) {
|
||||
return ;
|
||||
}
|
||||
|
||||
*((BOOLEAN *) Context) = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the ACK to get required information
|
||||
|
||||
@param Dhcp4 The DHCP4 protocol.
|
||||
@param Packet Packet waiting for parse.
|
||||
@param DnsServerInfor The required Dns4 server information.
|
||||
|
||||
@retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
|
||||
@retval EFI_NO_MAPPING DHCP failed to acquire address and other information.
|
||||
@retval EFI_DEVICE_ERROR Other errors as indicated.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
ParseDhcp4Ack (
|
||||
IN EFI_DHCP4_PROTOCOL *Dhcp4,
|
||||
IN EFI_DHCP4_PACKET *Packet,
|
||||
IN DNS4_SERVER_INFOR *DnsServerInfor
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 OptionCount;
|
||||
EFI_DHCP4_PACKET_OPTION **OptionList;
|
||||
UINT32 ServerCount;
|
||||
EFI_IPv4_ADDRESS *ServerList;
|
||||
UINT32 Index;
|
||||
UINT32 Count;
|
||||
|
||||
ServerCount = 0;
|
||||
ServerList = NULL;
|
||||
|
||||
OptionCount = 0;
|
||||
OptionList = NULL;
|
||||
|
||||
Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
|
||||
if (Status != EFI_BUFFER_TOO_SMALL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
|
||||
if (OptionList == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->FreePool (OptionList);
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
Status = EFI_NOT_FOUND;
|
||||
|
||||
for (Index = 0; Index < OptionCount; Index++) {
|
||||
//
|
||||
// Get DNS server addresses
|
||||
//
|
||||
if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
|
||||
|
||||
if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
ServerCount = OptionList[Index]->Length/4;
|
||||
ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS));
|
||||
if (ServerList == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
for(Count=0; Count < ServerCount; Count++){
|
||||
CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS));
|
||||
}
|
||||
|
||||
*(DnsServerInfor->ServerCount) = ServerCount;
|
||||
DnsServerInfor->ServerList = ServerList;
|
||||
|
||||
Status = EFI_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
gBS->FreePool (OptionList);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
|
||||
instance to intercept events that occurs in the DHCPv6 Information Request
|
||||
exchange process.
|
||||
|
||||
@param This Pointer to the EFI_DHCP6_PROTOCOL instance that
|
||||
is used to configure this callback function.
|
||||
@param Context Pointer to the context that is initialized in
|
||||
the EFI_DHCP6_PROTOCOL.InfoRequest().
|
||||
@param Packet Pointer to Reply packet that has been received.
|
||||
The EFI DHCPv6 Protocol instance is responsible
|
||||
for freeing the buffer.
|
||||
|
||||
@retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
|
||||
@retval EFI_DEVICE_ERROR Other errors as indicated.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
**/
|
||||
EFI_STATUS
|
||||
EFIAPI
|
||||
ParseDhcp6Ack (
|
||||
IN EFI_DHCP6_PROTOCOL *This,
|
||||
IN VOID *Context,
|
||||
IN EFI_DHCP6_PACKET *Packet
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
UINT32 OptionCount;
|
||||
EFI_DHCP6_PACKET_OPTION **OptionList;
|
||||
DNS6_SERVER_INFOR *DnsServerInfor;
|
||||
UINT32 ServerCount;
|
||||
EFI_IPv6_ADDRESS *ServerList;
|
||||
UINT32 Index;
|
||||
UINT32 Count;
|
||||
|
||||
OptionCount = 0;
|
||||
ServerCount = 0;
|
||||
ServerList = NULL;
|
||||
|
||||
Status = This->Parse (This, Packet, &OptionCount, NULL);
|
||||
if (Status != EFI_BUFFER_TOO_SMALL) {
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
|
||||
if (OptionList == NULL) {
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
Status = This->Parse (This, Packet, &OptionCount, OptionList);
|
||||
if (EFI_ERROR (Status)) {
|
||||
gBS->FreePool (OptionList);
|
||||
return EFI_DEVICE_ERROR;
|
||||
}
|
||||
|
||||
DnsServerInfor = (DNS6_SERVER_INFOR *) Context;
|
||||
|
||||
for (Index = 0; Index < OptionCount; Index++) {
|
||||
OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
|
||||
OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);
|
||||
|
||||
//
|
||||
// Get DNS server addresses from this reply packet.
|
||||
//
|
||||
if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) {
|
||||
|
||||
if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
|
||||
Status = EFI_DEVICE_ERROR;
|
||||
gBS->FreePool (OptionList);
|
||||
return Status;
|
||||
}
|
||||
|
||||
ServerCount = OptionList[Index]->OpLen/16;
|
||||
ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS));
|
||||
if (ServerList == NULL) {
|
||||
gBS->FreePool (OptionList);
|
||||
return EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
for(Count=0; Count < ServerCount; Count++){
|
||||
CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS));
|
||||
}
|
||||
|
||||
*(DnsServerInfor->ServerCount) = ServerCount;
|
||||
DnsServerInfor->ServerList = ServerList;
|
||||
}
|
||||
}
|
||||
|
||||
gBS->FreePool (OptionList);
|
||||
|
||||
return Status;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the DHCP ACK to get Dns4 server information.
|
||||
|
||||
@param Instance The DNS instance.
|
||||
@param DnsServerCount Retrieved Dns4 server Ip count.
|
||||
@param DnsServerList Retrieved Dns4 server Ip list.
|
||||
|
||||
@retval EFI_SUCCESS The Dns4 information is got from the DHCP ACK.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval EFI_NO_MEDIA There was a media error.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
GetDns4ServerFromDhcp4 (
|
||||
IN DNS_INSTANCE *Instance,
|
||||
OUT UINT32 *DnsServerCount,
|
||||
OUT EFI_IPv4_ADDRESS **DnsServerList
|
||||
)
|
||||
{
|
||||
EFI_STATUS Status;
|
||||
EFI_HANDLE Image;
|
||||
EFI_HANDLE Controller;
|
||||
BOOLEAN MediaPresent;
|
||||
EFI_HANDLE MnpChildHandle;
|
||||
EFI_MANAGED_NETWORK_PROTOCOL *Mnp;
|
||||
EFI_MANAGED_NETWORK_CONFIG_DATA MnpConfigData;
|
||||
EFI_HANDLE Dhcp4Handle;
|
||||
EFI_DHCP4_PROTOCOL *Dhcp4;
|
||||
EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
|
||||
UINTN DataSize;
|
||||
VOID *Data;
|
||||
EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo;
|
||||
EFI_DHCP4_PACKET SeedPacket;
|
||||
EFI_DHCP4_PACKET_OPTION *ParaList[2];
|
||||
DNS4_SERVER_INFOR DnsServerInfor;
|
||||
|
||||
EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN Token;
|
||||
BOOLEAN IsDone;
|
||||
UINTN Index;
|
||||
|
||||
Image = Instance->Service->ImageHandle;
|
||||
Controller = Instance->Service->ControllerHandle;
|
||||
|
||||
MnpChildHandle = NULL;
|
||||
Mnp = NULL;
|
||||
|
||||
Dhcp4Handle = NULL;
|
||||
Dhcp4 = NULL;
|
||||
|
||||
Ip4Config2 = NULL;
|
||||
DataSize = 0;
|
||||
Data = NULL;
|
||||
InterfaceInfo = NULL;
|
||||
|
||||
ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));
|
||||
|
||||
ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));
|
||||
|
||||
ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
|
||||
|
||||
DnsServerInfor.ServerCount = DnsServerCount;
|
||||
|
||||
IsDone = FALSE;
|
||||
|
||||
//
|
||||
// Check media.
|
||||
//
|
||||
MediaPresent = TRUE;
|
||||
NetLibDetectMedia (Controller, &MediaPresent);
|
||||
if (!MediaPresent) {
|
||||
return EFI_NO_MEDIA;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a Mnp child instance, get the protocol and config for it.
|
||||
//
|
||||
Status = NetLibCreateServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiManagedNetworkServiceBindingProtocolGuid,
|
||||
&MnpChildHandle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
MnpChildHandle,
|
||||
&gEfiManagedNetworkProtocolGuid,
|
||||
(VOID **) &Mnp,
|
||||
Image,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
MnpConfigData.ReceivedQueueTimeoutValue = 0;
|
||||
MnpConfigData.TransmitQueueTimeoutValue = 0;
|
||||
MnpConfigData.ProtocolTypeFilter = IP4_ETHER_PROTO;
|
||||
MnpConfigData.EnableUnicastReceive = TRUE;
|
||||
MnpConfigData.EnableMulticastReceive = TRUE;
|
||||
MnpConfigData.EnableBroadcastReceive = TRUE;
|
||||
MnpConfigData.EnablePromiscuousReceive = FALSE;
|
||||
MnpConfigData.FlushQueuesOnReset = TRUE;
|
||||
MnpConfigData.EnableReceiveTimestamps = FALSE;
|
||||
MnpConfigData.DisableBackgroundPolling = FALSE;
|
||||
|
||||
Status = Mnp->Configure(Mnp, &MnpConfigData);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a DHCP4 child instance and get the protocol.
|
||||
//
|
||||
Status = NetLibCreateServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiDhcp4ServiceBindingProtocolGuid,
|
||||
&Dhcp4Handle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
Dhcp4Handle,
|
||||
&gEfiDhcp4ProtocolGuid,
|
||||
(VOID **) &Dhcp4,
|
||||
Image,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Get Ip4Config2 instance info.
|
||||
//
|
||||
Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
|
||||
if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Data = AllocateZeroPool (DataSize);
|
||||
if (Data == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;
|
||||
|
||||
//
|
||||
// Build required Token.
|
||||
//
|
||||
Status = gBS->CreateEvent (
|
||||
EVT_NOTIFY_SIGNAL,
|
||||
TPL_NOTIFY,
|
||||
DhcpCommonNotify,
|
||||
&IsDone,
|
||||
&Token.CompletionEvent
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
|
||||
|
||||
Token.RemotePort = 67;
|
||||
|
||||
Token.ListenPointCount = 1;
|
||||
|
||||
Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
|
||||
if (Token.ListenPoints == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
if (Instance->Dns4CfgData.UseDefaultSetting) {
|
||||
CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
|
||||
CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
|
||||
} else {
|
||||
CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
|
||||
CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
|
||||
}
|
||||
|
||||
Token.ListenPoints[0].ListenPort = 68;
|
||||
|
||||
Token.TimeoutValue = DNS_TIME_TO_GETMAP;
|
||||
|
||||
DnsInitSeedPacket (&SeedPacket, InterfaceInfo);
|
||||
|
||||
ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
|
||||
if (ParaList[0] == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ParaList[0]->OpCode = DHCP4_TAG_TYPE;
|
||||
ParaList[0]->Length = 1;
|
||||
ParaList[0]->Data[0] = DHCP4_MSG_INFORM;
|
||||
|
||||
ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
|
||||
if (ParaList[1] == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
ParaList[1]->OpCode = DHCP4_TAG_PARA_LIST;
|
||||
ParaList[1]->Length = 1;
|
||||
ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;
|
||||
|
||||
Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);
|
||||
|
||||
Token.Packet->Dhcp4.Header.Xid = HTONL(NET_RANDOM (NetRandomInitSeed ()));
|
||||
|
||||
Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);
|
||||
|
||||
if (Instance->Dns4CfgData.UseDefaultSetting) {
|
||||
CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
|
||||
} else {
|
||||
CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
|
||||
}
|
||||
|
||||
CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);
|
||||
|
||||
Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);
|
||||
|
||||
//
|
||||
// TransmitReceive Token
|
||||
//
|
||||
Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Poll the packet
|
||||
//
|
||||
do {
|
||||
Status = Mnp->Poll (Mnp);
|
||||
} while (!IsDone);
|
||||
|
||||
//
|
||||
// Parse the ACK to get required information if received done.
|
||||
//
|
||||
if (IsDone && !EFI_ERROR (Token.Status)) {
|
||||
for (Index = 0; Index < Token.ResponseCount; Index++) {
|
||||
Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
|
||||
if (!EFI_ERROR (Status)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*DnsServerList = DnsServerInfor.ServerList;
|
||||
} else {
|
||||
Status = Token.Status;
|
||||
}
|
||||
|
||||
ON_EXIT:
|
||||
|
||||
if (Data != NULL) {
|
||||
FreePool (Data);
|
||||
}
|
||||
|
||||
for (Index = 0; Index < 2; Index++) {
|
||||
if (ParaList[Index] != NULL) {
|
||||
FreePool (ParaList[Index]);
|
||||
}
|
||||
}
|
||||
|
||||
if (Token.ListenPoints) {
|
||||
FreePool (Token.ListenPoints);
|
||||
}
|
||||
|
||||
if (Token.Packet) {
|
||||
FreePool (Token.Packet);
|
||||
}
|
||||
|
||||
if (Token.ResponseList != NULL) {
|
||||
FreePool (Token.ResponseList);
|
||||
}
|
||||
|
||||
if (Token.CompletionEvent != NULL) {
|
||||
gBS->CloseEvent (Token.CompletionEvent);
|
||||
}
|
||||
|
||||
if (Dhcp4 != NULL) {
|
||||
Dhcp4->Stop (Dhcp4);
|
||||
Dhcp4->Configure (Dhcp4, NULL);
|
||||
|
||||
gBS->CloseProtocol (
|
||||
Dhcp4Handle,
|
||||
&gEfiDhcp4ProtocolGuid,
|
||||
Image,
|
||||
Controller
|
||||
);
|
||||
}
|
||||
|
||||
if (Dhcp4Handle != NULL) {
|
||||
NetLibDestroyServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiDhcp4ServiceBindingProtocolGuid,
|
||||
Dhcp4Handle
|
||||
);
|
||||
}
|
||||
|
||||
if (Mnp != NULL) {
|
||||
Mnp->Configure (Mnp, NULL);
|
||||
|
||||
gBS->CloseProtocol (
|
||||
MnpChildHandle,
|
||||
&gEfiManagedNetworkProtocolGuid,
|
||||
Image,
|
||||
Controller
|
||||
);
|
||||
}
|
||||
|
||||
NetLibDestroyServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiManagedNetworkServiceBindingProtocolGuid,
|
||||
MnpChildHandle
|
||||
);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/**
|
||||
Parse the DHCP ACK to get Dns6 server information.
|
||||
|
||||
@param Image The handle of the driver image.
|
||||
@param Controller The handle of the controller.
|
||||
@param DnsServerCount Retrieved Dns6 server Ip count.
|
||||
@param DnsServerList Retrieved Dns6 server Ip list.
|
||||
|
||||
@retval EFI_SUCCESS The Dns6 information is got from the DHCP ACK.
|
||||
@retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
|
||||
@retval EFI_NO_MEDIA There was a media error.
|
||||
@retval Others Other errors as indicated.
|
||||
|
||||
**/
|
||||
EFI_STATUS
|
||||
GetDns6ServerFromDhcp6 (
|
||||
IN EFI_HANDLE Image,
|
||||
IN EFI_HANDLE Controller,
|
||||
OUT UINT32 *DnsServerCount,
|
||||
OUT EFI_IPv6_ADDRESS **DnsServerList
|
||||
)
|
||||
{
|
||||
EFI_HANDLE Dhcp6Handle;
|
||||
EFI_DHCP6_PROTOCOL *Dhcp6;
|
||||
EFI_STATUS Status;
|
||||
EFI_STATUS TimerStatus;
|
||||
EFI_DHCP6_PACKET_OPTION *Oro;
|
||||
EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
|
||||
EFI_EVENT Timer;
|
||||
BOOLEAN MediaPresent;
|
||||
DNS6_SERVER_INFOR DnsServerInfor;
|
||||
|
||||
Dhcp6Handle = NULL;
|
||||
Dhcp6 = NULL;
|
||||
Oro = NULL;
|
||||
Timer = NULL;
|
||||
|
||||
ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));
|
||||
|
||||
DnsServerInfor.ServerCount = DnsServerCount;
|
||||
|
||||
//
|
||||
// Check media status before doing DHCP.
|
||||
//
|
||||
MediaPresent = TRUE;
|
||||
NetLibDetectMedia (Controller, &MediaPresent);
|
||||
if (!MediaPresent) {
|
||||
return EFI_NO_MEDIA;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a DHCP6 child instance and get the protocol.
|
||||
//
|
||||
Status = NetLibCreateServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiDhcp6ServiceBindingProtocolGuid,
|
||||
&Dhcp6Handle
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = gBS->OpenProtocol (
|
||||
Dhcp6Handle,
|
||||
&gEfiDhcp6ProtocolGuid,
|
||||
(VOID **) &Dhcp6,
|
||||
Image,
|
||||
Controller,
|
||||
EFI_OPEN_PROTOCOL_BY_DRIVER
|
||||
);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
|
||||
if (Oro == NULL) {
|
||||
Status = EFI_OUT_OF_RESOURCES;
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
//
|
||||
// Ask the server to reply with DNS options.
|
||||
// All members in EFI_DHCP6_PACKET_OPTION are in network order.
|
||||
//
|
||||
Oro->OpCode = HTONS (DHCP6_TAG_DNS_REQUEST);
|
||||
Oro->OpLen = HTONS (2);
|
||||
Oro->Data[1] = DHCP6_TAG_DNS_SERVER;
|
||||
|
||||
InfoReqReXmit.Irt = 4;
|
||||
InfoReqReXmit.Mrc = 1;
|
||||
InfoReqReXmit.Mrt = 10;
|
||||
InfoReqReXmit.Mrd = 30;
|
||||
|
||||
Status = Dhcp6->InfoRequest (
|
||||
Dhcp6,
|
||||
TRUE,
|
||||
Oro,
|
||||
0,
|
||||
NULL,
|
||||
&InfoReqReXmit,
|
||||
NULL,
|
||||
ParseDhcp6Ack,
|
||||
&DnsServerInfor
|
||||
);
|
||||
if (Status == EFI_NO_MAPPING) {
|
||||
Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
Status = gBS->SetTimer (
|
||||
Timer,
|
||||
TimerRelative,
|
||||
DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
|
||||
);
|
||||
|
||||
if (EFI_ERROR (Status)) {
|
||||
goto ON_EXIT;
|
||||
}
|
||||
|
||||
do {
|
||||
TimerStatus = gBS->CheckEvent (Timer);
|
||||
if (!EFI_ERROR (TimerStatus)) {
|
||||
Status = Dhcp6->InfoRequest (
|
||||
Dhcp6,
|
||||
TRUE,
|
||||
Oro,
|
||||
0,
|
||||
NULL,
|
||||
&InfoReqReXmit,
|
||||
NULL,
|
||||
ParseDhcp6Ack,
|
||||
&DnsServerInfor
|
||||
);
|
||||
}
|
||||
} while (TimerStatus == EFI_NOT_READY);
|
||||
}
|
||||
|
||||
*DnsServerList = DnsServerInfor.ServerList;
|
||||
|
||||
ON_EXIT:
|
||||
|
||||
if (Oro != NULL) {
|
||||
FreePool (Oro);
|
||||
}
|
||||
|
||||
if (Timer != NULL) {
|
||||
gBS->CloseEvent (Timer);
|
||||
}
|
||||
|
||||
if (Dhcp6 != NULL) {
|
||||
gBS->CloseProtocol (
|
||||
Dhcp6Handle,
|
||||
&gEfiDhcp6ProtocolGuid,
|
||||
Image,
|
||||
Controller
|
||||
);
|
||||
}
|
||||
|
||||
NetLibDestroyServiceChild (
|
||||
Controller,
|
||||
Image,
|
||||
&gEfiDhcp6ServiceBindingProtocolGuid,
|
||||
Dhcp6Handle
|
||||
);
|
||||
|
||||
return Status;
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user