| /** @file | |
| Functions implementation related with DHCPv4/v6 for DNS driver. | |
| Copyright (c) 2015, Intel Corporation. All rights reserved.<BR> | |
| 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. | |
| **/ | |
| #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 ((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. | |
| // | |
| 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; | |
| } | |