VirtualBox

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

最後變更 在這個檔案從48674是 48674,由 vboxsync 提交於 11 年 前

EFI: Export newly imported tinaocore UEFI sources to OSE.

  • 屬性 svn:eol-style 設為 native
檔案大小: 13.9 KB
 
1/** @file
2 iSCSI DHCP6 related configuration routines.
3
4Copyright (c) 2009 - 2011, 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
254 OptionCount = 0;
255 BootFileOpt = NULL;
256
257 Status = This->Parse (This, Packet, &OptionCount, NULL);
258 if (Status != EFI_BUFFER_TOO_SMALL) {
259 return EFI_NOT_READY;
260 }
261
262 OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
263 if (OptionList == NULL) {
264 return EFI_NOT_READY;
265 }
266
267 Status = This->Parse (This, Packet, &OptionCount, OptionList);
268 if (EFI_ERROR (Status)) {
269 Status = EFI_NOT_READY;
270 goto Exit;
271 }
272
273 ConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) Context;
274
275 for (Index = 0; Index < OptionCount; Index++) {
276 OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
277 OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);
278
279 //
280 // Get DNS server addresses from this reply packet.
281 //
282 if (OptionList[Index]->OpCode == DHCP6_OPT_DNS_SERVERS) {
283
284 if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
285 Status = EFI_INVALID_PARAMETER;
286 goto Exit;
287 }
288 //
289 // Primary DNS server address.
290 //
291 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv6_ADDRESS));
292
293 if (OptionList[Index]->OpLen > 16) {
294 //
295 // Secondary DNS server address
296 //
297 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[16], sizeof (EFI_IPv6_ADDRESS));
298 }
299
300 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_URL) {
301 //
302 // The server sends this option to inform the client about an URL to a boot file.
303 //
304 BootFileOpt = OptionList[Index];
305 }
306 }
307
308 if (BootFileOpt == NULL) {
309 Status = EFI_UNSUPPORTED;
310 goto Exit;
311 }
312
313 //
314 // Get iSCSI root path from Boot File Uniform Resource Locator (URL) Option
315 //
316 Status = IScsiDhcp6ExtractRootPath (
317 (CHAR8 *) BootFileOpt->Data,
318 BootFileOpt->OpLen,
319 ConfigData
320 );
321
322Exit:
323
324 FreePool (OptionList);
325 return Status;
326}
327
328
329/**
330 Parse the DHCP ACK to get the address configuration and DNS information.
331
332 @param[in] Image The handle of the driver image.
333 @param[in] Controller The handle of the controller;
334 @param[in, out] ConfigData The attempt configuration data.
335
336 @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.
337 @retval EFI_NO_MAPPING DHCP failed to acquire address and other
338 information.
339 @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.
340 @retval EFI_DEVICE_ERROR Some unexpected error occurred.
341 @retval EFI_OUT_OF_RESOURCES There is no sufficient resource to finish the
342 operation.
343 @retval EFI_NO_MEDIA There was a media error.
344
345**/
346EFI_STATUS
347IScsiDoDhcp6 (
348 IN EFI_HANDLE Image,
349 IN EFI_HANDLE Controller,
350 IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData
351 )
352{
353 EFI_HANDLE Dhcp6Handle;
354 EFI_DHCP6_PROTOCOL *Dhcp6;
355 EFI_STATUS Status;
356 EFI_STATUS TimerStatus;
357 EFI_DHCP6_PACKET_OPTION *Oro;
358 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
359 EFI_EVENT Timer;
360 BOOLEAN MediaPresent;
361
362 //
363 // Check media status before doing DHCP.
364 //
365 MediaPresent = TRUE;
366 NetLibDetectMedia (Controller, &MediaPresent);
367 if (!MediaPresent) {
368 return EFI_NO_MEDIA;
369 }
370
371 //
372 // iSCSI will only request target info from DHCPv6 server.
373 //
374 if (!ConfigData->SessionConfigData.TargetInfoFromDhcp) {
375 return EFI_SUCCESS;
376 }
377
378 Dhcp6Handle = NULL;
379 Dhcp6 = NULL;
380 Oro = NULL;
381 Timer = NULL;
382
383 //
384 // Create a DHCP6 child instance and get the protocol.
385 //
386 Status = NetLibCreateServiceChild (
387 Controller,
388 Image,
389 &gEfiDhcp6ServiceBindingProtocolGuid,
390 &Dhcp6Handle
391 );
392 if (EFI_ERROR (Status)) {
393 return Status;
394 }
395
396 Status = gBS->OpenProtocol (
397 Dhcp6Handle,
398 &gEfiDhcp6ProtocolGuid,
399 (VOID **) &Dhcp6,
400 Image,
401 Controller,
402 EFI_OPEN_PROTOCOL_BY_DRIVER
403 );
404 if (EFI_ERROR (Status)) {
405 goto ON_EXIT;
406 }
407
408 Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 3);
409 if (Oro == NULL) {
410 Status = EFI_OUT_OF_RESOURCES;
411 goto ON_EXIT;
412 }
413
414 //
415 // Ask the server to reply with DNS and Boot File URL options by info request.
416 // All members in EFI_DHCP6_PACKET_OPTION are in network order.
417 //
418 Oro->OpCode = HTONS (DHCP6_OPT_REQUEST_OPTION);
419 Oro->OpLen = HTONS (2 * 2);
420 Oro->Data[1] = DHCP6_OPT_DNS_SERVERS;
421 Oro->Data[3] = DHCP6_OPT_BOOT_FILE_URL;
422
423 InfoReqReXmit.Irt = 4;
424 InfoReqReXmit.Mrc = 1;
425 InfoReqReXmit.Mrt = 10;
426 InfoReqReXmit.Mrd = 30;
427
428 Status = Dhcp6->InfoRequest (
429 Dhcp6,
430 TRUE,
431 Oro,
432 0,
433 NULL,
434 &InfoReqReXmit,
435 NULL,
436 IScsiDhcp6ParseReply,
437 ConfigData
438 );
439 if (Status == EFI_NO_MAPPING) {
440 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
441 if (EFI_ERROR (Status)) {
442 goto ON_EXIT;
443 }
444
445 Status = gBS->SetTimer (
446 Timer,
447 TimerRelative,
448 ISCSI_GET_MAPPING_TIMEOUT
449 );
450
451 if (EFI_ERROR (Status)) {
452 goto ON_EXIT;
453 }
454
455 do {
456
457 TimerStatus = gBS->CheckEvent (Timer);
458
459 if (!EFI_ERROR (TimerStatus)) {
460 Status = Dhcp6->InfoRequest (
461 Dhcp6,
462 TRUE,
463 Oro,
464 0,
465 NULL,
466 &InfoReqReXmit,
467 NULL,
468 IScsiDhcp6ParseReply,
469 ConfigData
470 );
471 }
472
473 } while (TimerStatus == EFI_NOT_READY);
474
475 }
476
477ON_EXIT:
478
479 if (Oro != NULL) {
480 FreePool (Oro);
481 }
482
483 if (Timer != NULL) {
484 gBS->CloseEvent (Timer);
485 }
486
487 if (Dhcp6 != NULL) {
488 gBS->CloseProtocol (
489 Dhcp6Handle,
490 &gEfiDhcp6ProtocolGuid,
491 Image,
492 Controller
493 );
494 }
495
496 NetLibDestroyServiceChild (
497 Controller,
498 Image,
499 &gEfiDhcp6ServiceBindingProtocolGuid,
500 Dhcp6Handle
501 );
502
503 return Status;
504}
505
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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