Home | History | Annotate | Download | only in HttpDxe
      1 /** @file
      2   Routines for HttpDxe driver to perform DNS resolution based on UEFI DNS protocols.
      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 "HttpDriver.h"
     16 
     17 /**
     18   Retrieve the host address using the EFI_DNS4_PROTOCOL.
     19 
     20   @param[in]  HttpInstance        Pointer to HTTP_PROTOCOL instance.
     21   @param[in]  HostName            Pointer to buffer containing hostname.
     22   @param[out] IpAddress           On output, pointer to buffer containing IPv4 address.
     23 
     24   @retval EFI_SUCCESS             Operation succeeded.
     25   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
     26   @retval EFI_DEVICE_ERROR        An unexpected network error occurred.
     27   @retval Others                  Other errors as indicated.
     28 
     29 **/
     30 EFI_STATUS
     31 HttpDns4 (
     32   IN     HTTP_PROTOCOL            *HttpInstance,
     33   IN     CHAR16                   *HostName,
     34      OUT EFI_IPv4_ADDRESS         *IpAddress
     35   )
     36 {
     37   EFI_STATUS                      Status;
     38   EFI_DNS4_PROTOCOL               *Dns4;
     39   EFI_DNS4_CONFIG_DATA            Dns4CfgData;
     40   EFI_DNS4_COMPLETION_TOKEN       Token;
     41   BOOLEAN                         IsDone;
     42   HTTP_SERVICE                    *Service;
     43   EFI_HANDLE                      Dns4Handle;
     44   EFI_IP4_CONFIG2_PROTOCOL        *Ip4Config2;
     45   UINTN                           DnsServerListCount;
     46   EFI_IPv4_ADDRESS                *DnsServerList;
     47   UINTN                           DataSize;
     48 
     49 
     50   Service = HttpInstance->Service;
     51   ASSERT (Service != NULL);
     52 
     53   DnsServerList      = NULL;
     54   DnsServerListCount = 0;
     55   ZeroMem (&Token, sizeof (EFI_DNS4_COMPLETION_TOKEN));
     56 
     57   //
     58   // Get DNS server list from EFI IPv4 Configuration II protocol.
     59   //
     60   Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp4Config2ProtocolGuid, (VOID **) &Ip4Config2);
     61   if (!EFI_ERROR (Status)) {
     62     //
     63     // Get the required size.
     64     //
     65     DataSize = 0;
     66     Status   = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, NULL);
     67     if (Status == EFI_BUFFER_TOO_SMALL) {
     68       DnsServerList = AllocatePool (DataSize);
     69       if (DnsServerList == NULL) {
     70         return EFI_OUT_OF_RESOURCES;
     71       }
     72 
     73       Status   = Ip4Config2->GetData (Ip4Config2, Ip4Config2DataTypeDnsServer, &DataSize, DnsServerList);
     74       if (EFI_ERROR (Status)) {
     75         FreePool (DnsServerList);
     76         DnsServerList = NULL;
     77       } else {
     78         DnsServerListCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
     79       }
     80     }
     81   }
     82 
     83   Dns4Handle = NULL;
     84   Dns4       = NULL;
     85 
     86   //
     87   // Create a DNS child instance and get the protocol.
     88   //
     89   Status = NetLibCreateServiceChild (
     90              Service->ControllerHandle,
     91              Service->ImageHandle,
     92              &gEfiDns4ServiceBindingProtocolGuid,
     93              &Dns4Handle
     94              );
     95   if (EFI_ERROR (Status)) {
     96     goto Exit;
     97   }
     98 
     99   Status = gBS->OpenProtocol (
    100                   Dns4Handle,
    101                   &gEfiDns4ProtocolGuid,
    102                   (VOID **) &Dns4,
    103                   Service->ImageHandle,
    104                   Service->ControllerHandle,
    105                   EFI_OPEN_PROTOCOL_BY_DRIVER
    106                   );
    107   if (EFI_ERROR (Status)) {
    108     goto Exit;
    109   }
    110 
    111   //
    112   // Configure DNS4 instance for the DNS server address and protocol.
    113   //
    114   ZeroMem (&Dns4CfgData, sizeof (Dns4CfgData));
    115   Dns4CfgData.DnsServerListCount = DnsServerListCount;
    116   Dns4CfgData.DnsServerList      = DnsServerList;
    117   Dns4CfgData.UseDefaultSetting  = HttpInstance->IPv4Node.UseDefaultAddress;
    118   if (!Dns4CfgData.UseDefaultSetting) {
    119     IP4_COPY_ADDRESS (&Dns4CfgData.StationIp, &HttpInstance->IPv4Node.LocalAddress);
    120     IP4_COPY_ADDRESS (&Dns4CfgData.SubnetMask, &HttpInstance->IPv4Node.LocalSubnet);
    121   }
    122   Dns4CfgData.EnableDnsCache     = TRUE;
    123   Dns4CfgData.Protocol           = EFI_IP_PROTO_UDP;
    124   Status = Dns4->Configure (
    125                    Dns4,
    126                    &Dns4CfgData
    127                    );
    128   if (EFI_ERROR (Status)) {
    129     goto Exit;
    130   }
    131 
    132   //
    133   // Create event to set the is done flag when name resolution is finished.
    134   //
    135   ZeroMem (&Token, sizeof (Token));
    136   Status = gBS->CreateEvent (
    137                   EVT_NOTIFY_SIGNAL,
    138                   TPL_NOTIFY,
    139                   HttpCommonNotify,
    140                   &IsDone,
    141                   &Token.Event
    142                   );
    143   if (EFI_ERROR (Status)) {
    144     goto Exit;
    145   }
    146 
    147   //
    148   // Start asynchronous name resolution.
    149   //
    150   Token.Status = EFI_NOT_READY;
    151   IsDone       = FALSE;
    152   Status = Dns4->HostNameToIp (Dns4, HostName, &Token);
    153   if (EFI_ERROR (Status)) {
    154     goto Exit;
    155   }
    156 
    157   while (!IsDone) {
    158     Dns4->Poll (Dns4);
    159   }
    160 
    161   //
    162   // Name resolution is done, check result.
    163   //
    164   Status = Token.Status;
    165   if (!EFI_ERROR (Status)) {
    166     if (Token.RspData.H2AData == NULL) {
    167       Status = EFI_DEVICE_ERROR;
    168       goto Exit;
    169     }
    170     if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {
    171       Status = EFI_DEVICE_ERROR;
    172       goto Exit;
    173     }
    174     //
    175     // We just return the first IP address from DNS protocol.
    176     //
    177     IP4_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);
    178     Status = EFI_SUCCESS;
    179   }
    180 
    181 Exit:
    182 
    183   if (Token.Event != NULL) {
    184     gBS->CloseEvent (Token.Event);
    185   }
    186   if (Token.RspData.H2AData != NULL) {
    187     if (Token.RspData.H2AData->IpList != NULL) {
    188       FreePool (Token.RspData.H2AData->IpList);
    189     }
    190     FreePool (Token.RspData.H2AData);
    191   }
    192 
    193   if (Dns4 != NULL) {
    194     Dns4->Configure (Dns4, NULL);
    195 
    196     gBS->CloseProtocol (
    197            Dns4Handle,
    198            &gEfiDns4ProtocolGuid,
    199            Service->ImageHandle,
    200            Service->ControllerHandle
    201            );
    202   }
    203 
    204   if (Dns4Handle != NULL) {
    205     NetLibDestroyServiceChild (
    206       Service->ControllerHandle,
    207       Service->ImageHandle,
    208       &gEfiDns4ServiceBindingProtocolGuid,
    209       Dns4Handle
    210       );
    211   }
    212 
    213   if (DnsServerList != NULL) {
    214     FreePool (DnsServerList);
    215   }
    216 
    217   return Status;
    218 }
    219 
    220 /**
    221   Retrieve the host address using the EFI_DNS6_PROTOCOL.
    222 
    223   @param[in]  HttpInstance        Pointer to HTTP_PROTOCOL instance.
    224   @param[in]  HostName            Pointer to buffer containing hostname.
    225   @param[out] IpAddress           On output, pointer to buffer containing IPv6 address.
    226 
    227   @retval EFI_SUCCESS             Operation succeeded.
    228   @retval EFI_OUT_OF_RESOURCES    Failed to allocate needed resources.
    229   @retval EFI_DEVICE_ERROR        An unexpected network error occurred.
    230   @retval Others                  Other errors as indicated.
    231 
    232 **/
    233 EFI_STATUS
    234 HttpDns6 (
    235   IN     HTTP_PROTOCOL            *HttpInstance,
    236   IN     CHAR16                   *HostName,
    237      OUT EFI_IPv6_ADDRESS         *IpAddress
    238   )
    239 {
    240   EFI_STATUS                      Status;
    241   HTTP_SERVICE                    *Service;
    242   EFI_DNS6_PROTOCOL               *Dns6;
    243   EFI_DNS6_CONFIG_DATA            Dns6ConfigData;
    244   EFI_DNS6_COMPLETION_TOKEN       Token;
    245   EFI_HANDLE                      Dns6Handle;
    246   EFI_IP6_CONFIG_PROTOCOL         *Ip6Config;
    247   EFI_IPv6_ADDRESS                *DnsServerList;
    248   UINTN                           DnsServerListCount;
    249   UINTN                           DataSize;
    250   BOOLEAN                         IsDone;
    251 
    252 
    253   Service = HttpInstance->Service;
    254   ASSERT (Service != NULL);
    255 
    256   DnsServerList       = NULL;
    257   DnsServerListCount  = 0;
    258   Dns6                = NULL;
    259   Dns6Handle          = NULL;
    260   ZeroMem (&Token, sizeof (EFI_DNS6_COMPLETION_TOKEN));
    261 
    262   //
    263   // Get DNS server list from EFI IPv6 Configuration protocol.
    264   //
    265   Status = gBS->HandleProtocol (Service->ControllerHandle, &gEfiIp6ConfigProtocolGuid, (VOID **) &Ip6Config);
    266   if (!EFI_ERROR (Status)) {
    267     //
    268     // Get the required size.
    269     //
    270     DataSize = 0;
    271     Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, NULL);
    272     if (Status == EFI_BUFFER_TOO_SMALL) {
    273       DnsServerList = AllocatePool (DataSize);
    274       if (DnsServerList == NULL) {
    275         return EFI_OUT_OF_RESOURCES;
    276       }
    277 
    278       Status = Ip6Config->GetData (Ip6Config, Ip6ConfigDataTypeDnsServer, &DataSize, DnsServerList);
    279       if (EFI_ERROR (Status)) {
    280         FreePool (DnsServerList);
    281         DnsServerList = NULL;
    282       } else {
    283         DnsServerListCount = DataSize / sizeof (EFI_IPv6_ADDRESS);
    284       }
    285     }
    286   }
    287 
    288   //
    289   // Create a DNSv6 child instance and get the protocol.
    290   //
    291   Status = NetLibCreateServiceChild (
    292              Service->ControllerHandle,
    293              Service->ImageHandle,
    294              &gEfiDns6ServiceBindingProtocolGuid,
    295              &Dns6Handle
    296              );
    297   if (EFI_ERROR (Status)) {
    298     goto Exit;
    299   }
    300 
    301   Status = gBS->OpenProtocol (
    302                   Dns6Handle,
    303                   &gEfiDns6ProtocolGuid,
    304                   (VOID **) &Dns6,
    305                   Service->ImageHandle,
    306                   Service->ControllerHandle,
    307                   EFI_OPEN_PROTOCOL_BY_DRIVER
    308                   );
    309   if (EFI_ERROR (Status)) {
    310     goto Exit;
    311   }
    312 
    313   //
    314   // Configure DNS6 instance for the DNS server address and protocol.
    315   //
    316   ZeroMem (&Dns6ConfigData, sizeof (EFI_DNS6_CONFIG_DATA));
    317   Dns6ConfigData.DnsServerCount = (UINT32)DnsServerListCount;
    318   Dns6ConfigData.DnsServerList  = DnsServerList;
    319   Dns6ConfigData.EnableDnsCache = TRUE;
    320   Dns6ConfigData.Protocol       = EFI_IP_PROTO_UDP;
    321   IP6_COPY_ADDRESS (&Dns6ConfigData.StationIp, &HttpInstance->Ipv6Node.LocalAddress);
    322   Status = Dns6->Configure (
    323                    Dns6,
    324                    &Dns6ConfigData
    325                    );
    326   if (EFI_ERROR (Status)) {
    327     goto Exit;
    328   }
    329 
    330   Token.Status = EFI_NOT_READY;
    331   IsDone       = FALSE;
    332   //
    333   // Create event to set the  IsDone flag when name resolution is finished.
    334   //
    335   Status = gBS->CreateEvent (
    336                   EVT_NOTIFY_SIGNAL,
    337                   TPL_NOTIFY,
    338                   HttpCommonNotify,
    339                   &IsDone,
    340                   &Token.Event
    341                   );
    342   if (EFI_ERROR (Status)) {
    343     goto Exit;
    344   }
    345 
    346   //
    347   // Start asynchronous name resolution.
    348   //
    349   Status = Dns6->HostNameToIp (Dns6, HostName, &Token);
    350   if (EFI_ERROR (Status)) {
    351     goto Exit;
    352   }
    353 
    354   while (!IsDone) {
    355     Dns6->Poll (Dns6);
    356   }
    357 
    358   //
    359   // Name resolution is done, check result.
    360   //
    361   Status = Token.Status;
    362   if (!EFI_ERROR (Status)) {
    363     if (Token.RspData.H2AData == NULL) {
    364       Status = EFI_DEVICE_ERROR;
    365       goto Exit;
    366     }
    367     if (Token.RspData.H2AData->IpCount == 0 || Token.RspData.H2AData->IpList == NULL) {
    368       Status = EFI_DEVICE_ERROR;
    369       goto Exit;
    370     }
    371     //
    372     // We just return the first IPv6 address from DNS protocol.
    373     //
    374     IP6_COPY_ADDRESS (IpAddress, Token.RspData.H2AData->IpList);
    375     Status = EFI_SUCCESS;
    376   }
    377 
    378 Exit:
    379 
    380   if (Token.Event != NULL) {
    381     gBS->CloseEvent (Token.Event);
    382   }
    383   if (Token.RspData.H2AData != NULL) {
    384     if (Token.RspData.H2AData->IpList != NULL) {
    385       FreePool (Token.RspData.H2AData->IpList);
    386     }
    387     FreePool (Token.RspData.H2AData);
    388   }
    389 
    390   if (Dns6 != NULL) {
    391     Dns6->Configure (Dns6, NULL);
    392 
    393     gBS->CloseProtocol (
    394            Dns6Handle,
    395            &gEfiDns6ProtocolGuid,
    396            Service->ImageHandle,
    397            Service->ControllerHandle
    398            );
    399   }
    400 
    401   if (Dns6Handle != NULL) {
    402     NetLibDestroyServiceChild (
    403       Service->ControllerHandle,
    404       Service->ImageHandle,
    405       &gEfiDns6ServiceBindingProtocolGuid,
    406       Dns6Handle
    407       );
    408   }
    409 
    410   if (DnsServerList != NULL) {
    411     FreePool (DnsServerList);
    412   }
    413 
    414   return Status;
    415 }
    416