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