NetworkPkg:Enable Http Boot over Ipv6 stack
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpDns.c
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 }