summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/DnsDxe/DnsDhcp.c
diff options
context:
space:
mode:
authorjiaxinwu <jiaxin.wu@intel.com>2015-07-07 08:22:03 +0000
committerjiaxinwu <jiaxinwu@Edk2>2015-07-07 08:22:03 +0000
commit99c048ef4aca44589d519946ee6a6c890ad9123b (patch)
treeda327aeb9a98a8e7e5ac1ceaf774efce2d76d4ec /NetworkPkg/DnsDxe/DnsDhcp.c
parent1f6729ffe98095107ce82e67a4a0209674601a90 (diff)
downloadedk2-99c048ef4aca44589d519946ee6a6c890ad9123b.tar.gz
edk2-99c048ef4aca44589d519946ee6a6c890ad9123b.tar.bz2
edk2-99c048ef4aca44589d519946ee6a6c890ad9123b.zip
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
Diffstat (limited to 'NetworkPkg/DnsDxe/DnsDhcp.c')
-rw-r--r--NetworkPkg/DnsDxe/DnsDhcp.c762
1 files changed, 762 insertions, 0 deletions
diff --git a/NetworkPkg/DnsDxe/DnsDhcp.c b/NetworkPkg/DnsDxe/DnsDhcp.c
new file mode 100644
index 0000000000..4607f7b633
--- /dev/null
+++ b/NetworkPkg/DnsDxe/DnsDhcp.c
@@ -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;
+
+}
+