/** @file | |
Functions implementation related with DHCPv4/v6 for DNS driver. | |
Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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; | |
EFI_STATUS MediaStatus; | |
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 ((UINT8 *)ParaList, sizeof (ParaList)); | |
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. | |
// | |
MediaStatus = EFI_SUCCESS; | |
NetLibDetectMediaWaitTimeout (Controller, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus); | |
if (MediaStatus != EFI_SUCCESS) { | |
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_REQUEST; | |
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; | |
EFI_STATUS MediaStatus; | |
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. | |
// | |
MediaStatus = EFI_SUCCESS; | |
NetLibDetectMediaWaitTimeout (Controller, DNS_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus); | |
if (MediaStatus != EFI_SUCCESS) { | |
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; | |
} |