This patch is used to update the DnsDhcp.c to use BSD license. Cc: Ye Ting <ting.ye@intel.com> Cc: Siyuan Fu <siyuan.fu@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Jiaxin Wu <jiaxin.wu@intel.com> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com> Reviewed-by: Ye Ting <ting.ye@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@18315 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			921 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			921 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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"
 | |
| 
 | |
| /**
 | |
|   The callback function for the timer event used to get map.
 | |
| 
 | |
|   @param[in] Event    The event this function is registered to.
 | |
|   @param[in] Context  The context registered to the event.
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| TimeoutToGetMap (
 | |
|   IN EFI_EVENT      Event,
 | |
|   IN VOID           *Context
 | |
|   )
 | |
| {
 | |
|   *((BOOLEAN *) Context) = TRUE;
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Create an IP child, use it to start the auto configuration, then destroy it.
 | |
| 
 | |
|   @param[in] Controller       The controller which has the service installed.
 | |
|   @param[in] Image            The image handle used to open service.
 | |
| 
 | |
|   @retval EFI_SUCCESS         The configuration is done.
 | |
|   @retval Others              Other errors as indicated.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| DnsStartIp4(
 | |
|   IN  EFI_HANDLE            Controller,
 | |
|   IN  EFI_HANDLE            Image
 | |
|   )
 | |
| {
 | |
|   EFI_IP4_PROTOCOL              *Ip4;
 | |
|   EFI_HANDLE                    Ip4Handle;
 | |
|   EFI_EVENT                     TimerToGetMap;
 | |
|   EFI_IP4_CONFIG_DATA           Ip4ConfigData;
 | |
|   EFI_IP4_MODE_DATA             Ip4Mode;
 | |
|   EFI_STATUS                    Status;
 | |
| 
 | |
|   BOOLEAN                       Timeout;
 | |
| 
 | |
|   //
 | |
|   // Get the Ip4ServiceBinding Protocol
 | |
|   //
 | |
|   Ip4Handle     = NULL;
 | |
|   Ip4           = NULL;
 | |
|   TimerToGetMap = NULL;
 | |
|   
 | |
|   Timeout      = FALSE;
 | |
| 
 | |
|   Status = NetLibCreateServiceChild (
 | |
|              Controller,
 | |
|              Image,
 | |
|              &gEfiIp4ServiceBindingProtocolGuid,
 | |
|              &Ip4Handle
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                  Ip4Handle,
 | |
|                  &gEfiIp4ProtocolGuid,
 | |
|                  (VOID **) &Ip4,
 | |
|                  Controller,
 | |
|                  Image,
 | |
|                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                  );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Ip4ConfigData.DefaultProtocol          = EFI_IP_PROTO_ICMP;
 | |
|   Ip4ConfigData.AcceptAnyProtocol        = FALSE;
 | |
|   Ip4ConfigData.AcceptIcmpErrors         = FALSE;
 | |
|   Ip4ConfigData.AcceptBroadcast          = FALSE;
 | |
|   Ip4ConfigData.AcceptPromiscuous        = FALSE;
 | |
|   Ip4ConfigData.UseDefaultAddress        = TRUE;
 | |
|   ZeroMem (&Ip4ConfigData.StationAddress, sizeof (EFI_IPv4_ADDRESS));
 | |
|   ZeroMem (&Ip4ConfigData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | |
|   Ip4ConfigData.TypeOfService            = 0;
 | |
|   Ip4ConfigData.TimeToLive               = 1;
 | |
|   Ip4ConfigData.DoNotFragment            = FALSE;
 | |
|   Ip4ConfigData.RawData                  = FALSE;
 | |
|   Ip4ConfigData.ReceiveTimeout           = 0;
 | |
|   Ip4ConfigData.TransmitTimeout          = 0;
 | |
| 
 | |
|   Status = Ip4->Configure (Ip4, &Ip4ConfigData);
 | |
| 
 | |
|   if (Status == EFI_NO_MAPPING) {
 | |
|     Status  = gBS->CreateEvent (
 | |
|                     EVT_NOTIFY_SIGNAL | EVT_TIMER,
 | |
|                     TPL_CALLBACK,
 | |
|                     TimeoutToGetMap,
 | |
|                     &Timeout,
 | |
|                     &TimerToGetMap
 | |
|                     );
 | |
|     
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     
 | |
|     Status = gBS->SetTimer (
 | |
|                    TimerToGetMap,
 | |
|                    TimerRelative,
 | |
|                    MultU64x32 (10000000, 5)
 | |
|                    );
 | |
|     
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|     
 | |
|     while (!Timeout) {
 | |
|       Ip4->Poll (Ip4);
 | |
|   
 | |
|       if (!EFI_ERROR (Ip4->GetModeData (Ip4, &Ip4Mode, NULL, NULL)) && 
 | |
|           Ip4Mode.IsConfigured) {       
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     if (Timeout) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|     }
 | |
|   }
 | |
|   
 | |
| ON_EXIT: 
 | |
| 
 | |
|   if (TimerToGetMap != NULL) {
 | |
|     gBS->SetTimer (TimerToGetMap, TimerCancel, 0);
 | |
|     gBS->CloseEvent (TimerToGetMap);
 | |
|   }
 | |
| 
 | |
|   NetLibDestroyServiceChild (
 | |
|     Controller,
 | |
|     Image,
 | |
|     &gEfiIp4ServiceBindingProtocolGuid,
 | |
|     Ip4Handle
 | |
|     );
 | |
|   
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Start the auto configuration if UseDefaultSetting.
 | |
|   //
 | |
|   if (Instance->Dns4CfgData.UseDefaultSetting) {
 | |
|     Status = DnsStartIp4 (Controller, Image);
 | |
|     if (EFI_ERROR(Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // 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;
 | |
|   
 | |
| }
 | |
| 
 |