VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiDhcp6.c@ 59499

Last change on this file since 59499 was 58466, checked in by vboxsync, 9 years ago

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

  • Property svn:eol-style set to native
File size: 14.6 KB
Line 
1/** @file
2 iSCSI DHCP6 related configuration routines.
3
4Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "IScsiImpl.h"
16
17
18/**
19 Extract the Root Path option and get the required target information from
20 Boot File Uniform Resource Locator (URL) Option.
21
22 @param[in] RootPath The RootPath string.
23 @param[in] Length Length of the RootPath option payload.
24 @param[in, out] ConfigData The iSCSI session configuration data read from
25 nonvolatile device.
26
27 @retval EFI_SUCCESS All required information is extracted from the
28 RootPath option.
29 @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.
30 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
31 @retval EFI_INVALID_PARAMETER The RootPath is malformatted.
32
33**/
34EFI_STATUS
35IScsiDhcp6ExtractRootPath (
36 IN CHAR8 *RootPath,
37 IN UINT16 Length,
38 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData
39 )
40{
41 EFI_STATUS Status;
42 UINT16 IScsiRootPathIdLen;
43 CHAR8 *TmpStr;
44 ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];
45 ISCSI_ROOT_PATH_FIELD *Field;
46 UINT32 FieldIndex;
47 UINT8 Index;
48 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
49 EFI_IP_ADDRESS Ip;
50 UINT8 IpMode;
51
52 ConfigNvData = &ConfigData->SessionConfigData;
53
54 //
55 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
56 //
57 IScsiRootPathIdLen = (UINT16) AsciiStrLen (ISCSI_ROOT_PATH_ID);
58
59 if ((Length <= IScsiRootPathIdLen) ||
60 (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {
61 return EFI_NOT_FOUND;
62 }
63 //
64 // Skip the iSCSI RootPath ID "iscsi:".
65 //
66 RootPath = RootPath + IScsiRootPathIdLen;
67 Length = (UINT16) (Length - IScsiRootPathIdLen);
68
69 TmpStr = (CHAR8 *) AllocatePool (Length + 1);
70 if (TmpStr == NULL) {
71 return EFI_OUT_OF_RESOURCES;
72 }
73
74 CopyMem (TmpStr, RootPath, Length);
75 TmpStr[Length] = '\0';
76
77 Index = 0;
78 FieldIndex = 0;
79 ZeroMem (&Fields[0], sizeof (Fields));
80
81 //
82 // Extract SERVERNAME field in the Root Path option.
83 //
84 if (TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_START_DELIMITER) {
85 Status = EFI_INVALID_PARAMETER;
86 goto ON_EXIT;
87 } else {
88 Index++;
89 }
90
91 Fields[RP_FIELD_IDX_SERVERNAME].Str = &TmpStr[Index];
92
93 while ((TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_END_DELIMITER) && (Index < Length)) {
94 Index++;
95 }
96
97 //
98 // Skip ']' and ':'.
99 //
100 TmpStr[Index] = '\0';
101 Index += 2;
102
103 Fields[RP_FIELD_IDX_SERVERNAME].Len = (UINT8) AsciiStrLen (Fields[RP_FIELD_IDX_SERVERNAME].Str);
104
105 //
106 // Extract others fields in the Root Path option string.
107 //
108 for (FieldIndex = 1; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {
109
110 if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {
111 Fields[FieldIndex].Str = &TmpStr[Index];
112 }
113
114 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
115 Index++;
116 }
117
118 if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {
119 if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {
120 TmpStr[Index] = '\0';
121 Index++;
122 }
123
124 if (Fields[FieldIndex].Str != NULL) {
125 Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);
126 }
127 }
128 }
129
130 if (FieldIndex != RP_FIELD_IDX_MAX) {
131 Status = EFI_INVALID_PARAMETER;
132 goto ON_EXIT;
133 }
134
135 if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||
136 (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||
137 (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)
138 ) {
139
140 Status = EFI_INVALID_PARAMETER;
141 goto ON_EXIT;
142 }
143 //
144 // Get the IP address of the target.
145 //
146 Field = &Fields[RP_FIELD_IDX_SERVERNAME];
147 if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {
148 IpMode = ConfigNvData->IpMode;
149 } else {
150 IpMode = ConfigData->AutoConfigureMode;
151 }
152
153 Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);
154 CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));
155
156
157 if (EFI_ERROR (Status)) {
158 goto ON_EXIT;
159 }
160 //
161 // Check the protocol type.
162 //
163 Field = &Fields[RP_FIELD_IDX_PROTOCOL];
164 if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {
165 Status = EFI_INVALID_PARAMETER;
166 goto ON_EXIT;
167 }
168 //
169 // Get the port of the iSCSI target.
170 //
171 Field = &Fields[RP_FIELD_IDX_PORT];
172 if (Field->Str != NULL) {
173 ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);
174 } else {
175 ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
176 }
177 //
178 // Get the LUN.
179 //
180 Field = &Fields[RP_FIELD_IDX_LUN];
181 if (Field->Str != NULL) {
182 Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);
183 if (EFI_ERROR (Status)) {
184 goto ON_EXIT;
185 }
186 } else {
187 ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));
188 }
189 //
190 // Get the target iSCSI Name.
191 //
192 Field = &Fields[RP_FIELD_IDX_TARGETNAME];
193
194 if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {
195 Status = EFI_INVALID_PARAMETER;
196 goto ON_EXIT;
197 }
198 //
199 // Validate the iSCSI name.
200 //
201 Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));
202 if (EFI_ERROR (Status)) {
203 goto ON_EXIT;
204 }
205
206 AsciiStrCpy (ConfigNvData->TargetName, Field->Str);
207
208ON_EXIT:
209
210 FreePool (TmpStr);
211
212 return Status;
213}
214
215/**
216 EFI_DHCP6_INFO_CALLBACK is provided by the consumer of the EFI DHCPv6 Protocol
217 instance to intercept events that occurs in the DHCPv6 Information Request
218 exchange process.
219
220 @param[in] This Pointer to the EFI_DHCP6_PROTOCOL instance that
221 is used to configure this callback function.
222 @param[in] Context Pointer to the context that is initialized in
223 the EFI_DHCP6_PROTOCOL.InfoRequest().
224 @param[in] Packet Pointer to Reply packet that has been received.
225 The EFI DHCPv6 Protocol instance is responsible
226 for freeing the buffer.
227
228 @retval EFI_SUCCESS Tell the EFI DHCPv6 Protocol instance to finish
229 Information Request exchange process.
230 @retval EFI_NOT_READY Tell the EFI DHCPv6 Protocol instance to continue
231 Information Request exchange process.
232 @retval EFI_ABORTED Tell the EFI DHCPv6 Protocol instance to abort
233 the Information Request exchange process.
234 @retval EFI_UNSUPPORTED Tell the EFI DHCPv6 Protocol instance to finish
235 the Information Request exchange process because some
236 request information are not received.
237
238**/
239EFI_STATUS
240EFIAPI
241IScsiDhcp6ParseReply (
242 IN EFI_DHCP6_PROTOCOL *This,
243 IN VOID *Context,
244 IN EFI_DHCP6_PACKET *Packet
245 )
246{
247 EFI_STATUS Status;
248 UINT32 Index;
249 UINT32 OptionCount;
250 EFI_DHCP6_PACKET_OPTION *BootFileOpt;
251 EFI_DHCP6_PACKET_OPTION **OptionList;
252 ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData;
253 UINT16 ParaLen;
254
255 OptionCount = 0;
256 BootFileOpt = NULL;
257
258 Status = This->Parse (This, Packet, &OptionCount, NULL);
259 if (Status != EFI_BUFFER_TOO_SMALL) {
260 return EFI_NOT_READY;
261 }
262
263 OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
264 if (OptionList == NULL) {
265 return EFI_NOT_READY;
266 }
267
268 Status = This->Parse (This, Packet, &OptionCount, OptionList);
269 if (EFI_ERROR (Status)) {
270 Status = EFI_NOT_READY;
271 goto Exit;
272 }
273
274 ConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context;
275
276 for (Index = 0; Index < OptionCount; Index++) {
277 OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
278 OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);
279
280 //
281 // Get DNS server addresses from this reply packet.
282 //
283 if (OptionList[Index]->OpCode == DHCP6_OPT_DNS_SERVERS) {
284
285 if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
286 Status = EFI_UNSUPPORTED;
287 goto Exit;
288 }
289 //
290 // Primary DNS server address.
291 //
292 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv6_ADDRESS));
293
294 if (OptionList[Index]->OpLen > 16) {
295 //
296 // Secondary DNS server address
297 //
298 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[16], sizeof (EFI_IPv6_ADDRESS));
299 }
300
301 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_URL) {
302 //
303 // The server sends this option to inform the client about an URL to a boot file.
304 //
305 BootFileOpt = OptionList[Index];
306 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_PARA) {
307 //
308 // The server sends this option to inform the client about DHCP6 server address.
309 //
310 if (OptionList[Index]->OpLen < 18) {
311 Status = EFI_UNSUPPORTED;
312 goto Exit;
313 }
314 //
315 // Check param-len 1, should be 16 bytes.
316 //
317 CopyMem (&ParaLen, &OptionList[Index]->Data[0], sizeof (UINT16));
318 if (NTOHS (ParaLen) != 16) {
319 Status = EFI_UNSUPPORTED;
320 goto Exit;
321 }
322
323 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[2], sizeof (EFI_IPv6_ADDRESS));
324 }
325 }
326
327 if (BootFileOpt == NULL) {
328 Status = EFI_UNSUPPORTED;
329 goto Exit;
330 }
331
332 //
333 // Get iSCSI root path from Boot File Uniform Resource Locator (URL) Option
334 //
335 Status = IScsiDhcp6ExtractRootPath (
336 (CHAR8 *) BootFileOpt->Data,
337 BootFileOpt->OpLen,
338 ConfigData
339 );
340
341Exit:
342
343 FreePool (OptionList);
344 return Status;
345}
346
347
348/**
349 Parse the DHCP ACK to get the address configuration and DNS information.
350
351 @param[in] Image The handle of the driver image.
352 @param[in] Controller The handle of the controller;
353 @param[in, out] ConfigData The attempt configuration data.
354
355 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
356 @retval EFI_NO_MAPPING DHCP failed to acquire address and other
357 information.
358 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.
359 @retval EFI_DEVICE_ERROR Some unexpected error occurred.
360 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to finish the
361 operation.
362 @retval EFI_NO_MEDIA There was a media error.
363
364**/
365EFI_STATUS
366IScsiDoDhcp6 (
367 IN EFI_HANDLE Image,
368 IN EFI_HANDLE Controller,
369 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData
370 )
371{
372 EFI_HANDLE Dhcp6Handle;
373 EFI_DHCP6_PROTOCOL *Dhcp6;
374 EFI_STATUS Status;
375 EFI_STATUS TimerStatus;
376 EFI_DHCP6_PACKET_OPTION *Oro;
377 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
378 EFI_EVENT Timer;
379 BOOLEAN MediaPresent;
380
381 //
382 // Check media status before doing DHCP.
383 //
384 MediaPresent = TRUE;
385 NetLibDetectMedia (Controller, &MediaPresent);
386 if (!MediaPresent) {
387 return EFI_NO_MEDIA;
388 }
389
390 //
391 // iSCSI will only request target info from DHCPv6 server.
392 //
393 if (!ConfigData->SessionConfigData.TargetInfoFromDhcp) {
394 return EFI_SUCCESS;
395 }
396
397 Dhcp6Handle = NULL;
398 Dhcp6 = NULL;
399 Oro = NULL;
400 Timer = NULL;
401
402 //
403 // Create a DHCP6 child instance and get the protocol.
404 //
405 Status = NetLibCreateServiceChild (
406 Controller,
407 Image,
408 &gEfiDhcp6ServiceBindingProtocolGuid,
409 &Dhcp6Handle
410 );
411 if (EFI_ERROR (Status)) {
412 return Status;
413 }
414
415 Status = gBS->OpenProtocol (
416 Dhcp6Handle,
417 &gEfiDhcp6ProtocolGuid,
418 (VOID **) &Dhcp6,
419 Image,
420 Controller,
421 EFI_OPEN_PROTOCOL_BY_DRIVER
422 );
423 if (EFI_ERROR (Status)) {
424 goto ON_EXIT;
425 }
426
427 Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 5);
428 if (Oro == NULL) {
429 Status = EFI_OUT_OF_RESOURCES;
430 goto ON_EXIT;
431 }
432
433 //
434 // Ask the server to reply with DNS and Boot File URL options by info request.
435 // All members in EFI_DHCP6_PACKET_OPTION are in network order.
436 //
437 Oro->OpCode = HTONS (DHCP6_OPT_REQUEST_OPTION);
438 Oro->OpLen = HTONS (2 * 3);
439 Oro->Data[1] = DHCP6_OPT_DNS_SERVERS;
440 Oro->Data[3] = DHCP6_OPT_BOOT_FILE_URL;
441 Oro->Data[5] = DHCP6_OPT_BOOT_FILE_PARA;
442
443 InfoReqReXmit.Irt = 4;
444 InfoReqReXmit.Mrc = 1;
445 InfoReqReXmit.Mrt = 10;
446 InfoReqReXmit.Mrd = 30;
447
448 Status = Dhcp6->InfoRequest (
449 Dhcp6,
450 TRUE,
451 Oro,
452 0,
453 NULL,
454 &InfoReqReXmit,
455 NULL,
456 IScsiDhcp6ParseReply,
457 ConfigData
458 );
459 if (Status == EFI_NO_MAPPING) {
460 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
461 if (EFI_ERROR (Status)) {
462 goto ON_EXIT;
463 }
464
465 Status = gBS->SetTimer (
466 Timer,
467 TimerRelative,
468 ISCSI_GET_MAPPING_TIMEOUT
469 );
470
471 if (EFI_ERROR (Status)) {
472 goto ON_EXIT;
473 }
474
475 do {
476
477 TimerStatus = gBS->CheckEvent (Timer);
478
479 if (!EFI_ERROR (TimerStatus)) {
480 Status = Dhcp6->InfoRequest (
481 Dhcp6,
482 TRUE,
483 Oro,
484 0,
485 NULL,
486 &InfoReqReXmit,
487 NULL,
488 IScsiDhcp6ParseReply,
489 ConfigData
490 );
491 }
492
493 } while (TimerStatus == EFI_NOT_READY);
494
495 }
496
497ON_EXIT:
498
499 if (Oro != NULL) {
500 FreePool (Oro);
501 }
502
503 if (Timer != NULL) {
504 gBS->CloseEvent (Timer);
505 }
506
507 if (Dhcp6 != NULL) {
508 gBS->CloseProtocol (
509 Dhcp6Handle,
510 &gEfiDhcp6ProtocolGuid,
511 Image,
512 Controller
513 );
514 }
515
516 NetLibDestroyServiceChild (
517 Controller,
518 Image,
519 &gEfiDhcp6ServiceBindingProtocolGuid,
520 Dhcp6Handle
521 );
522
523 return Status;
524}
525
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette