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