Home | History | Annotate | Download | only in DnsDxe
      1 /** @file
      2 Functions implementation related with DHCPv4/v6 for DNS driver.
      3 
      4 Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "DnsImpl.h"
     16 
     17 /**
     18   This function initialize the DHCP4 message instance.
     19 
     20   This function will pad each item of dhcp4 message packet.
     21 
     22   @param  Seed             Pointer to the message instance of the DHCP4 packet.
     23   @param  InterfaceInfo    Pointer to the EFI_IP4_CONFIG2_INTERFACE_INFO instance.
     24 
     25 **/
     26 VOID
     27 DnsInitSeedPacket (
     28   OUT EFI_DHCP4_PACKET               *Seed,
     29   IN  EFI_IP4_CONFIG2_INTERFACE_INFO *InterfaceInfo
     30   )
     31 {
     32   EFI_DHCP4_HEADER           *Header;
     33 
     34   //
     35   // Get IfType and HwAddressSize from SNP mode data.
     36   //
     37   Seed->Size            = sizeof (EFI_DHCP4_PACKET);
     38   Seed->Length          = sizeof (Seed->Dhcp4);
     39   Header                = &Seed->Dhcp4.Header;
     40   ZeroMem (Header, sizeof (EFI_DHCP4_HEADER));
     41   Header->OpCode        = DHCP4_OPCODE_REQUEST;
     42   Header->HwType        = InterfaceInfo->IfType;
     43   Header->HwAddrLen     = (UINT8) InterfaceInfo->HwAddressSize;
     44   CopyMem (Header->ClientHwAddr, &(InterfaceInfo->HwAddress), Header->HwAddrLen);
     45 
     46   Seed->Dhcp4.Magik     = DHCP4_MAGIC;
     47   Seed->Dhcp4.Option[0] = DHCP4_TAG_EOP;
     48 }
     49 
     50 /**
     51   The common notify function.
     52 
     53   @param[in]  Event   The event signaled.
     54   @param[in]  Context The context.
     55 
     56 **/
     57 VOID
     58 EFIAPI
     59 DhcpCommonNotify (
     60   IN EFI_EVENT  Event,
     61   IN VOID       *Context
     62   )
     63 {
     64   if ((Event == NULL) || (Context == NULL)) {
     65     return ;
     66   }
     67 
     68   *((BOOLEAN *) Context) = TRUE;
     69 }
     70 
     71 /**
     72   Parse the ACK to get required information
     73 
     74   @param  Dhcp4            The DHCP4 protocol.
     75   @param  Packet           Packet waiting for parse.
     76   @param  DnsServerInfor   The required Dns4 server information.
     77 
     78   @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
     79   @retval EFI_NO_MAPPING        DHCP failed to acquire address and other information.
     80   @retval EFI_DEVICE_ERROR      Other errors as indicated.
     81   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
     82 
     83 **/
     84 EFI_STATUS
     85 ParseDhcp4Ack (
     86   IN EFI_DHCP4_PROTOCOL         *Dhcp4,
     87   IN EFI_DHCP4_PACKET           *Packet,
     88   IN DNS4_SERVER_INFOR          *DnsServerInfor
     89   )
     90 {
     91   EFI_STATUS              Status;
     92   UINT32                  OptionCount;
     93   EFI_DHCP4_PACKET_OPTION **OptionList;
     94   UINT32                  ServerCount;
     95   EFI_IPv4_ADDRESS        *ServerList;
     96   UINT32                  Index;
     97   UINT32                  Count;
     98 
     99   ServerCount = 0;
    100   ServerList = NULL;
    101 
    102   OptionCount = 0;
    103   OptionList  = NULL;
    104 
    105   Status      = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
    106   if (Status != EFI_BUFFER_TOO_SMALL) {
    107     return EFI_DEVICE_ERROR;
    108   }
    109 
    110   OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
    111   if (OptionList == NULL) {
    112     return EFI_OUT_OF_RESOURCES;
    113   }
    114 
    115   Status = Dhcp4->Parse (Dhcp4, Packet, &OptionCount, OptionList);
    116   if (EFI_ERROR (Status)) {
    117     gBS->FreePool (OptionList);
    118     return EFI_DEVICE_ERROR;
    119   }
    120 
    121   Status = EFI_NOT_FOUND;
    122 
    123   for (Index = 0; Index < OptionCount; Index++) {
    124     //
    125     // Get DNS server addresses
    126     //
    127     if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
    128 
    129       if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
    130         Status = EFI_DEVICE_ERROR;
    131         break;
    132       }
    133 
    134       ServerCount = OptionList[Index]->Length/4;
    135       ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv4_ADDRESS));
    136       if (ServerList == NULL) {
    137         return EFI_OUT_OF_RESOURCES;
    138       }
    139 
    140       for(Count=0; Count < ServerCount; Count++){
    141         CopyMem (ServerList + Count, &OptionList[Index]->Data[4 * Count], sizeof (EFI_IPv4_ADDRESS));
    142       }
    143 
    144       *(DnsServerInfor->ServerCount) = ServerCount;
    145       DnsServerInfor->ServerList     = ServerList;
    146 
    147       Status = EFI_SUCCESS;
    148     }
    149   }
    150 
    151   gBS->FreePool (OptionList);
    152 
    153   return Status;
    154 }
    155 
    156 /**
    157   EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
    158   instance to intercept events that occurs in the DHCPv6 Information Request
    159   exchange process.
    160 
    161   @param  This                  Pointer to the EFI_DHCP6_PROTOCOL instance that
    162                                 is used to configure this  callback function.
    163   @param  Context               Pointer to the context that is initialized in
    164                                 the EFI_DHCP6_PROTOCOL.InfoRequest().
    165   @param  Packet                Pointer to Reply packet that has been received.
    166                                 The EFI DHCPv6 Protocol instance is responsible
    167                                 for freeing the buffer.
    168 
    169   @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
    170   @retval EFI_DEVICE_ERROR      Other errors as indicated.
    171   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
    172 **/
    173 EFI_STATUS
    174 EFIAPI
    175 ParseDhcp6Ack (
    176   IN EFI_DHCP6_PROTOCOL          *This,
    177   IN VOID                        *Context,
    178   IN EFI_DHCP6_PACKET            *Packet
    179   )
    180 {
    181   EFI_STATUS                  Status;
    182   UINT32                      OptionCount;
    183   EFI_DHCP6_PACKET_OPTION     **OptionList;
    184   DNS6_SERVER_INFOR           *DnsServerInfor;
    185   UINT32                      ServerCount;
    186   EFI_IPv6_ADDRESS            *ServerList;
    187   UINT32                      Index;
    188   UINT32                      Count;
    189 
    190   OptionCount = 0;
    191   ServerCount = 0;
    192   ServerList  = NULL;
    193 
    194   Status      = This->Parse (This, Packet, &OptionCount, NULL);
    195   if (Status != EFI_BUFFER_TOO_SMALL) {
    196     return EFI_DEVICE_ERROR;
    197   }
    198 
    199   OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
    200   if (OptionList == NULL) {
    201     return EFI_OUT_OF_RESOURCES;
    202   }
    203 
    204   Status = This->Parse (This, Packet, &OptionCount, OptionList);
    205   if (EFI_ERROR (Status)) {
    206     gBS->FreePool (OptionList);
    207     return EFI_DEVICE_ERROR;
    208   }
    209 
    210   DnsServerInfor = (DNS6_SERVER_INFOR *) Context;
    211 
    212   for (Index = 0; Index < OptionCount; Index++) {
    213     OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
    214     OptionList[Index]->OpLen  = NTOHS (OptionList[Index]->OpLen);
    215 
    216     //
    217     // Get DNS server addresses from this reply packet.
    218     //
    219     if (OptionList[Index]->OpCode == DHCP6_TAG_DNS_SERVER) {
    220 
    221       if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
    222         Status = EFI_DEVICE_ERROR;
    223         gBS->FreePool (OptionList);
    224         return Status;
    225       }
    226 
    227       ServerCount = OptionList[Index]->OpLen/16;
    228       ServerList = AllocatePool (ServerCount * sizeof (EFI_IPv6_ADDRESS));
    229       if (ServerList == NULL) {
    230         gBS->FreePool (OptionList);
    231         return EFI_OUT_OF_RESOURCES;
    232       }
    233 
    234       for(Count=0; Count < ServerCount; Count++){
    235         CopyMem (ServerList + Count, &OptionList[Index]->Data[16 * Count], sizeof (EFI_IPv6_ADDRESS));
    236       }
    237 
    238       *(DnsServerInfor->ServerCount) = ServerCount;
    239       DnsServerInfor->ServerList     = ServerList;
    240     }
    241   }
    242 
    243   gBS->FreePool (OptionList);
    244 
    245   return Status;
    246 
    247 }
    248 
    249 /**
    250   Parse the DHCP ACK to get Dns4 server information.
    251 
    252   @param  Instance         The DNS instance.
    253   @param  DnsServerCount   Retrieved Dns4 server Ip count.
    254   @param  DnsServerList    Retrieved Dns4 server Ip list.
    255 
    256   @retval EFI_SUCCESS           The Dns4 information is got from the DHCP ACK.
    257   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
    258   @retval EFI_NO_MEDIA          There was a media error.
    259   @retval Others                Other errors as indicated.
    260 
    261 **/
    262 EFI_STATUS
    263 GetDns4ServerFromDhcp4 (
    264   IN  DNS_INSTANCE               *Instance,
    265   OUT UINT32                     *DnsServerCount,
    266   OUT EFI_IPv4_ADDRESS           **DnsServerList
    267   )
    268 {
    269   EFI_STATUS                          Status;
    270   EFI_HANDLE                          Image;
    271   EFI_HANDLE                          Controller;
    272   BOOLEAN                             MediaPresent;
    273   EFI_HANDLE                          MnpChildHandle;
    274   EFI_MANAGED_NETWORK_PROTOCOL        *Mnp;
    275   EFI_MANAGED_NETWORK_CONFIG_DATA     MnpConfigData;
    276   EFI_HANDLE                          Dhcp4Handle;
    277   EFI_DHCP4_PROTOCOL                  *Dhcp4;
    278   EFI_IP4_CONFIG2_PROTOCOL            *Ip4Config2;
    279   UINTN                               DataSize;
    280   VOID                                *Data;
    281   EFI_IP4_CONFIG2_INTERFACE_INFO      *InterfaceInfo;
    282   EFI_DHCP4_PACKET                    SeedPacket;
    283   EFI_DHCP4_PACKET_OPTION             *ParaList[2];
    284   DNS4_SERVER_INFOR                   DnsServerInfor;
    285 
    286   EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN    Token;
    287   BOOLEAN                             IsDone;
    288   UINTN                               Index;
    289 
    290   Image                      = Instance->Service->ImageHandle;
    291   Controller                 = Instance->Service->ControllerHandle;
    292 
    293   MnpChildHandle             = NULL;
    294   Mnp                        = NULL;
    295 
    296   Dhcp4Handle                = NULL;
    297   Dhcp4                      = NULL;
    298 
    299   Ip4Config2                 = NULL;
    300   DataSize                   = 0;
    301   Data                       = NULL;
    302   InterfaceInfo              = NULL;
    303 
    304   ZeroMem ((UINT8 *) ParaList, sizeof (ParaList));
    305 
    306   ZeroMem (&MnpConfigData, sizeof (EFI_MANAGED_NETWORK_CONFIG_DATA));
    307 
    308   ZeroMem (&DnsServerInfor, sizeof (DNS4_SERVER_INFOR));
    309 
    310   ZeroMem (&Token, sizeof (EFI_DHCP4_TRANSMIT_RECEIVE_TOKEN));
    311 
    312   DnsServerInfor.ServerCount = DnsServerCount;
    313 
    314   IsDone = FALSE;
    315 
    316   //
    317   // Check media.
    318   //
    319   MediaPresent = TRUE;
    320   NetLibDetectMedia (Controller, &MediaPresent);
    321   if (!MediaPresent) {
    322     return EFI_NO_MEDIA;
    323   }
    324 
    325   //
    326   // Create a Mnp child instance, get the protocol and config for it.
    327   //
    328   Status = NetLibCreateServiceChild (
    329              Controller,
    330              Image,
    331              &gEfiManagedNetworkServiceBindingProtocolGuid,
    332              &MnpChildHandle
    333              );
    334   if (EFI_ERROR (Status)) {
    335     return Status;
    336   }
    337 
    338   Status = gBS->OpenProtocol (
    339                   MnpChildHandle,
    340                   &gEfiManagedNetworkProtocolGuid,
    341                   (VOID **) &Mnp,
    342                   Image,
    343                   Controller,
    344                   EFI_OPEN_PROTOCOL_BY_DRIVER
    345                   );
    346   if (EFI_ERROR (Status)) {
    347     goto ON_EXIT;
    348   }
    349 
    350   MnpConfigData.ReceivedQueueTimeoutValue = 0;
    351   MnpConfigData.TransmitQueueTimeoutValue = 0;
    352   MnpConfigData.ProtocolTypeFilter        = IP4_ETHER_PROTO;
    353   MnpConfigData.EnableUnicastReceive      = TRUE;
    354   MnpConfigData.EnableMulticastReceive    = TRUE;
    355   MnpConfigData.EnableBroadcastReceive    = TRUE;
    356   MnpConfigData.EnablePromiscuousReceive  = FALSE;
    357   MnpConfigData.FlushQueuesOnReset        = TRUE;
    358   MnpConfigData.EnableReceiveTimestamps   = FALSE;
    359   MnpConfigData.DisableBackgroundPolling  = FALSE;
    360 
    361   Status = Mnp->Configure(Mnp, &MnpConfigData);
    362   if (EFI_ERROR (Status)) {
    363     goto ON_EXIT;
    364   }
    365 
    366   //
    367   // Create a DHCP4 child instance and get the protocol.
    368   //
    369   Status = NetLibCreateServiceChild (
    370              Controller,
    371              Image,
    372              &gEfiDhcp4ServiceBindingProtocolGuid,
    373              &Dhcp4Handle
    374              );
    375   if (EFI_ERROR (Status)) {
    376     goto ON_EXIT;
    377   }
    378 
    379   Status = gBS->OpenProtocol (
    380                   Dhcp4Handle,
    381                   &gEfiDhcp4ProtocolGuid,
    382                   (VOID **) &Dhcp4,
    383                   Image,
    384                   Controller,
    385                   EFI_OPEN_PROTOCOL_BY_DRIVER
    386                   );
    387   if (EFI_ERROR (Status)) {
    388     goto ON_EXIT;
    389   }
    390 
    391   //
    392   // Get Ip4Config2 instance info.
    393   //
    394   Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
    395   if (EFI_ERROR (Status)) {
    396     goto ON_EXIT;
    397   }
    398 
    399   Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
    400   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
    401     goto ON_EXIT;
    402   }
    403 
    404   Data = AllocateZeroPool (DataSize);
    405   if (Data == NULL) {
    406     Status = EFI_OUT_OF_RESOURCES;
    407     goto ON_EXIT;
    408   }
    409 
    410   Status = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeInterfaceInfo, &DataSize, Data);
    411   if (EFI_ERROR (Status)) {
    412     goto ON_EXIT;
    413   }
    414 
    415   InterfaceInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *)Data;
    416 
    417   //
    418   // Build required Token.
    419   //
    420   Status = gBS->CreateEvent (
    421                   EVT_NOTIFY_SIGNAL,
    422                   TPL_NOTIFY,
    423                   DhcpCommonNotify,
    424                   &IsDone,
    425                   &Token.CompletionEvent
    426                   );
    427   if (EFI_ERROR (Status)) {
    428     goto ON_EXIT;
    429   }
    430 
    431   SetMem (&Token.RemoteAddress, sizeof (EFI_IPv4_ADDRESS), 0xff);
    432 
    433   Token.RemotePort = 67;
    434 
    435   Token.ListenPointCount = 1;
    436 
    437   Token.ListenPoints = AllocateZeroPool (Token.ListenPointCount * sizeof (EFI_DHCP4_LISTEN_POINT));
    438   if (Token.ListenPoints == NULL) {
    439     Status = EFI_OUT_OF_RESOURCES;
    440     goto ON_EXIT;
    441   }
    442 
    443   if (Instance->Dns4CfgData.UseDefaultSetting) {
    444     CopyMem (&(Token.ListenPoints[0].ListenAddress), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
    445     CopyMem (&(Token.ListenPoints[0].SubnetMask), &(InterfaceInfo->SubnetMask), sizeof (EFI_IPv4_ADDRESS));
    446   } else {
    447     CopyMem (&(Token.ListenPoints[0].ListenAddress), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
    448     CopyMem (&(Token.ListenPoints[0].SubnetMask), &(Instance->Dns4CfgData.SubnetMask), sizeof (EFI_IPv4_ADDRESS));
    449   }
    450 
    451   Token.ListenPoints[0].ListenPort = 68;
    452 
    453   Token.TimeoutValue = DNS_TIME_TO_GETMAP;
    454 
    455   DnsInitSeedPacket (&SeedPacket, InterfaceInfo);
    456 
    457   ParaList[0] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
    458   if (ParaList[0] == NULL) {
    459     Status = EFI_OUT_OF_RESOURCES;
    460     goto ON_EXIT;
    461   }
    462 
    463   ParaList[0]->OpCode  = DHCP4_TAG_TYPE;
    464   ParaList[0]->Length  = 1;
    465   ParaList[0]->Data[0] = DHCP4_MSG_INFORM;
    466 
    467   ParaList[1] = AllocateZeroPool (sizeof (EFI_DHCP4_PACKET_OPTION));
    468   if (ParaList[1] == NULL) {
    469     Status = EFI_OUT_OF_RESOURCES;
    470     goto ON_EXIT;
    471   }
    472 
    473   ParaList[1]->OpCode  = DHCP4_TAG_PARA_LIST;
    474   ParaList[1]->Length  = 1;
    475   ParaList[1]->Data[0] = DHCP4_TAG_DNS_SERVER;
    476 
    477   Status = Dhcp4->Build (Dhcp4, &SeedPacket, 0, NULL, 2, ParaList, &Token.Packet);
    478 
    479   Token.Packet->Dhcp4.Header.Xid      = HTONL(NET_RANDOM (NetRandomInitSeed ()));
    480 
    481   Token.Packet->Dhcp4.Header.Reserved = HTONS ((UINT16)0x8000);
    482 
    483   if (Instance->Dns4CfgData.UseDefaultSetting) {
    484     CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(InterfaceInfo->StationAddress), sizeof (EFI_IPv4_ADDRESS));
    485   } else {
    486     CopyMem (&(Token.Packet->Dhcp4.Header.ClientAddr), &(Instance->Dns4CfgData.StationIp), sizeof (EFI_IPv4_ADDRESS));
    487   }
    488 
    489   CopyMem (Token.Packet->Dhcp4.Header.ClientHwAddr, &(InterfaceInfo->HwAddress), InterfaceInfo->HwAddressSize);
    490 
    491   Token.Packet->Dhcp4.Header.HwAddrLen = (UINT8)(InterfaceInfo->HwAddressSize);
    492 
    493   //
    494   // TransmitReceive Token
    495   //
    496   Status = Dhcp4->TransmitReceive (Dhcp4, &Token);
    497   if (EFI_ERROR (Status)) {
    498     goto ON_EXIT;
    499   }
    500 
    501   //
    502   // Poll the packet
    503   //
    504   do {
    505     Status = Mnp->Poll (Mnp);
    506   } while (!IsDone);
    507 
    508   //
    509   // Parse the ACK to get required information if received done.
    510   //
    511   if (IsDone && !EFI_ERROR (Token.Status)) {
    512     for (Index = 0; Index < Token.ResponseCount; Index++) {
    513       Status = ParseDhcp4Ack (Dhcp4, &Token.ResponseList[Index], &DnsServerInfor);
    514       if (!EFI_ERROR (Status)) {
    515         break;
    516       }
    517     }
    518 
    519     *DnsServerList = DnsServerInfor.ServerList;
    520   } else {
    521     Status = Token.Status;
    522   }
    523 
    524 ON_EXIT:
    525 
    526   if (Data != NULL) {
    527     FreePool (Data);
    528   }
    529 
    530   for (Index = 0; Index < 2; Index++) {
    531     if (ParaList[Index] != NULL) {
    532       FreePool (ParaList[Index]);
    533     }
    534   }
    535 
    536   if (Token.ListenPoints) {
    537     FreePool (Token.ListenPoints);
    538   }
    539 
    540   if (Token.Packet) {
    541     FreePool (Token.Packet);
    542   }
    543 
    544   if (Token.ResponseList != NULL) {
    545     FreePool (Token.ResponseList);
    546   }
    547 
    548   if (Token.CompletionEvent != NULL) {
    549     gBS->CloseEvent (Token.CompletionEvent);
    550   }
    551 
    552   if (Dhcp4 != NULL) {
    553     Dhcp4->Stop (Dhcp4);
    554     Dhcp4->Configure (Dhcp4, NULL);
    555 
    556     gBS->CloseProtocol (
    557            Dhcp4Handle,
    558            &gEfiDhcp4ProtocolGuid,
    559            Image,
    560            Controller
    561            );
    562   }
    563 
    564   if (Dhcp4Handle != NULL) {
    565     NetLibDestroyServiceChild (
    566       Controller,
    567       Image,
    568       &gEfiDhcp4ServiceBindingProtocolGuid,
    569       Dhcp4Handle
    570       );
    571   }
    572 
    573   if (Mnp != NULL) {
    574     Mnp->Configure (Mnp, NULL);
    575 
    576     gBS->CloseProtocol (
    577            MnpChildHandle,
    578            &gEfiManagedNetworkProtocolGuid,
    579            Image,
    580            Controller
    581            );
    582   }
    583 
    584   NetLibDestroyServiceChild (
    585     Controller,
    586     Image,
    587     &gEfiManagedNetworkServiceBindingProtocolGuid,
    588     MnpChildHandle
    589     );
    590 
    591   return Status;
    592 }
    593 
    594 /**
    595   Parse the DHCP ACK to get Dns6 server information.
    596 
    597   @param  Image            The handle of the driver image.
    598   @param  Controller       The handle of the controller.
    599   @param  DnsServerCount   Retrieved Dns6 server Ip count.
    600   @param  DnsServerList    Retrieved Dns6 server Ip list.
    601 
    602   @retval EFI_SUCCESS           The Dns6 information is got from the DHCP ACK.
    603   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
    604   @retval EFI_NO_MEDIA          There was a media error.
    605   @retval Others                Other errors as indicated.
    606 
    607 **/
    608 EFI_STATUS
    609 GetDns6ServerFromDhcp6 (
    610   IN  EFI_HANDLE                 Image,
    611   IN  EFI_HANDLE                 Controller,
    612   OUT UINT32                     *DnsServerCount,
    613   OUT EFI_IPv6_ADDRESS           **DnsServerList
    614   )
    615 {
    616   EFI_HANDLE                Dhcp6Handle;
    617   EFI_DHCP6_PROTOCOL        *Dhcp6;
    618   EFI_STATUS                Status;
    619   EFI_STATUS                TimerStatus;
    620   EFI_DHCP6_PACKET_OPTION   *Oro;
    621   EFI_DHCP6_RETRANSMISSION  InfoReqReXmit;
    622   EFI_EVENT                 Timer;
    623   BOOLEAN                   MediaPresent;
    624   DNS6_SERVER_INFOR         DnsServerInfor;
    625 
    626   Dhcp6Handle = NULL;
    627   Dhcp6       = NULL;
    628   Oro         = NULL;
    629   Timer       = NULL;
    630 
    631   ZeroMem (&DnsServerInfor, sizeof (DNS6_SERVER_INFOR));
    632 
    633   DnsServerInfor.ServerCount = DnsServerCount;
    634 
    635   //
    636   // Check media status before doing DHCP.
    637   //
    638   MediaPresent = TRUE;
    639   NetLibDetectMedia (Controller, &MediaPresent);
    640   if (!MediaPresent) {
    641     return EFI_NO_MEDIA;
    642   }
    643 
    644   //
    645   // Create a DHCP6 child instance and get the protocol.
    646   //
    647   Status = NetLibCreateServiceChild (
    648              Controller,
    649              Image,
    650              &gEfiDhcp6ServiceBindingProtocolGuid,
    651              &Dhcp6Handle
    652              );
    653   if (EFI_ERROR (Status)) {
    654     return Status;
    655   }
    656 
    657   Status = gBS->OpenProtocol (
    658                   Dhcp6Handle,
    659                   &gEfiDhcp6ProtocolGuid,
    660                   (VOID **) &Dhcp6,
    661                   Image,
    662                   Controller,
    663                   EFI_OPEN_PROTOCOL_BY_DRIVER
    664                   );
    665   if (EFI_ERROR (Status)) {
    666     goto ON_EXIT;
    667   }
    668 
    669   Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 1);
    670   if (Oro == NULL) {
    671     Status = EFI_OUT_OF_RESOURCES;
    672     goto ON_EXIT;
    673   }
    674 
    675   //
    676   // Ask the server to reply with DNS options.
    677   // All members in EFI_DHCP6_PACKET_OPTION are in network order.
    678   //
    679   Oro->OpCode  = HTONS (DHCP6_TAG_DNS_REQUEST);
    680   Oro->OpLen   = HTONS (2);
    681   Oro->Data[1] = DHCP6_TAG_DNS_SERVER;
    682 
    683   InfoReqReXmit.Irt = 4;
    684   InfoReqReXmit.Mrc = 1;
    685   InfoReqReXmit.Mrt = 10;
    686   InfoReqReXmit.Mrd = 30;
    687 
    688   Status = Dhcp6->InfoRequest (
    689                     Dhcp6,
    690                     TRUE,
    691                     Oro,
    692                     0,
    693                     NULL,
    694                     &InfoReqReXmit,
    695                     NULL,
    696                     ParseDhcp6Ack,
    697                     &DnsServerInfor
    698                     );
    699   if (Status == EFI_NO_MAPPING) {
    700     Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
    701     if (EFI_ERROR (Status)) {
    702       goto ON_EXIT;
    703     }
    704 
    705     Status = gBS->SetTimer (
    706                     Timer,
    707                     TimerRelative,
    708                     DNS_TIME_TO_GETMAP * TICKS_PER_SECOND
    709                     );
    710 
    711     if (EFI_ERROR (Status)) {
    712       goto ON_EXIT;
    713     }
    714 
    715     do {
    716       TimerStatus = gBS->CheckEvent (Timer);
    717       if (!EFI_ERROR (TimerStatus)) {
    718         Status = Dhcp6->InfoRequest (
    719                           Dhcp6,
    720                           TRUE,
    721                           Oro,
    722                           0,
    723                           NULL,
    724                           &InfoReqReXmit,
    725                           NULL,
    726                           ParseDhcp6Ack,
    727                           &DnsServerInfor
    728                           );
    729       }
    730     } while (TimerStatus == EFI_NOT_READY);
    731   }
    732 
    733   *DnsServerList  = DnsServerInfor.ServerList;
    734 
    735 ON_EXIT:
    736 
    737   if (Oro != NULL) {
    738     FreePool (Oro);
    739   }
    740 
    741   if (Timer != NULL) {
    742     gBS->CloseEvent (Timer);
    743   }
    744 
    745   if (Dhcp6 != NULL) {
    746     gBS->CloseProtocol (
    747            Dhcp6Handle,
    748            &gEfiDhcp6ProtocolGuid,
    749            Image,
    750            Controller
    751            );
    752   }
    753 
    754   NetLibDestroyServiceChild (
    755     Controller,
    756     Image,
    757     &gEfiDhcp6ServiceBindingProtocolGuid,
    758     Dhcp6Handle
    759     );
    760 
    761   return Status;
    762 
    763 }
    764 
    765