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