TianoCore EDK2 master
Loading...
Searching...
No Matches
IScsiDhcp6.c
Go to the documentation of this file.
1
9#include "IScsiImpl.h"
10
29 IN CHAR8 *RootPath,
30 IN UINT16 Length,
32 )
33{
34 EFI_STATUS Status;
35 UINT16 IScsiRootPathIdLen;
36 CHAR8 *TmpStr;
37 ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];
39 UINT32 FieldIndex;
40 UINT8 Index;
41 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
43 UINT8 IpMode;
44
45 ConfigNvData = &ConfigData->SessionConfigData;
46 ConfigNvData->DnsMode = FALSE;
47 //
48 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
49 //
50 IScsiRootPathIdLen = (UINT16)AsciiStrLen (ISCSI_ROOT_PATH_ID);
51
52 if ((Length <= IScsiRootPathIdLen) ||
53 (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0))
54 {
55 return EFI_NOT_FOUND;
56 }
57
58 //
59 // Skip the iSCSI RootPath ID "iscsi:".
60 //
61 RootPath = RootPath + IScsiRootPathIdLen;
62 Length = (UINT16)(Length - IScsiRootPathIdLen);
63
64 TmpStr = (CHAR8 *)AllocatePool (Length + 1);
65 if (TmpStr == NULL) {
66 return EFI_OUT_OF_RESOURCES;
67 }
68
69 CopyMem (TmpStr, RootPath, Length);
70 TmpStr[Length] = '\0';
71
72 Index = 0;
73 FieldIndex = 0;
74 ZeroMem (&Fields[0], sizeof (Fields));
75
76 //
77 // Extract SERVERNAME field in the Root Path option.
78 //
79 if (TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_START_DELIMITER) {
80 //
81 // The servername is expressed as domain name.
82 //
83 ConfigNvData->DnsMode = TRUE;
84 } else {
85 Index++;
86 }
87
88 Fields[RP_FIELD_IDX_SERVERNAME].Str = &TmpStr[Index];
89
90 if (!ConfigNvData->DnsMode) {
91 while ((TmpStr[Index] != ISCSI_ROOT_PATH_ADDR_END_DELIMITER) && (Index < Length)) {
92 Index++;
93 }
94
95 //
96 // Skip ']' and ':'.
97 //
98 TmpStr[Index] = '\0';
99 Index += 2;
100 } else {
101 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
102 Index++;
103 }
104
105 //
106 // Skip ':'.
107 //
108 TmpStr[Index] = '\0';
109 Index += 1;
110 }
111
112 Fields[RP_FIELD_IDX_SERVERNAME].Len = (UINT8)AsciiStrLen (Fields[RP_FIELD_IDX_SERVERNAME].Str);
113
114 //
115 // Extract others fields in the Root Path option string.
116 //
117 for (FieldIndex = 1; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {
118 if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {
119 Fields[FieldIndex].Str = &TmpStr[Index];
120 }
121
122 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
123 Index++;
124 }
125
126 if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {
127 if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {
128 TmpStr[Index] = '\0';
129 Index++;
130 }
131
132 if (Fields[FieldIndex].Str != NULL) {
133 Fields[FieldIndex].Len = (UINT8)AsciiStrLen (Fields[FieldIndex].Str);
134 }
135 }
136 }
137
138 if (FieldIndex != RP_FIELD_IDX_MAX) {
139 Status = EFI_INVALID_PARAMETER;
140 goto ON_EXIT;
141 }
142
143 if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||
144 (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||
145 (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)
146 )
147 {
148 Status = EFI_INVALID_PARAMETER;
149 goto ON_EXIT;
150 }
151
152 //
153 // Get the IP address of the target.
154 //
155 Field = &Fields[RP_FIELD_IDX_SERVERNAME];
156 if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {
157 IpMode = ConfigNvData->IpMode;
158 } else {
159 IpMode = ConfigData->AutoConfigureMode;
160 }
161
162 //
163 // Server name is expressed as domain name, just save it.
164 //
165 if (ConfigNvData->DnsMode) {
166 if ((Field->Len + 2) > sizeof (ConfigNvData->TargetUrl)) {
167 return EFI_INVALID_PARAMETER;
168 }
169
170 CopyMem (&ConfigNvData->TargetUrl, Field->Str, Field->Len);
171 ConfigNvData->TargetUrl[Field->Len + 1] = '\0';
172 } else {
173 ZeroMem (&ConfigNvData->TargetUrl, sizeof (ConfigNvData->TargetUrl));
174 Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);
175 CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));
176
177 if (EFI_ERROR (Status)) {
178 goto ON_EXIT;
179 }
180 }
181
182 //
183 // Check the protocol type.
184 //
185 Field = &Fields[RP_FIELD_IDX_PROTOCOL];
186 if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {
187 Status = EFI_INVALID_PARAMETER;
188 goto ON_EXIT;
189 }
190
191 //
192 // Get the port of the iSCSI target.
193 //
194 Field = &Fields[RP_FIELD_IDX_PORT];
195 if (Field->Str != NULL) {
196 ConfigNvData->TargetPort = (UINT16)AsciiStrDecimalToUintn (Field->Str);
197 } else {
198 ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
199 }
200
201 //
202 // Get the LUN.
203 //
204 Field = &Fields[RP_FIELD_IDX_LUN];
205 if (Field->Str != NULL) {
206 Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);
207 if (EFI_ERROR (Status)) {
208 goto ON_EXIT;
209 }
210 } else {
211 ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));
212 }
213
214 //
215 // Get the target iSCSI Name.
216 //
217 Field = &Fields[RP_FIELD_IDX_TARGETNAME];
218
219 if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {
220 Status = EFI_INVALID_PARAMETER;
221 goto ON_EXIT;
222 }
223
224 //
225 // Validate the iSCSI name.
226 //
227 Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));
228 if (EFI_ERROR (Status)) {
229 goto ON_EXIT;
230 }
231
232 AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);
233
234ON_EXIT:
235
236 FreePool (TmpStr);
237
238 return Status;
239}
240
266EFIAPI
269 IN VOID *Context,
270 IN EFI_DHCP6_PACKET *Packet
271 )
272{
273 EFI_STATUS Status;
274 UINT32 Index;
275 UINT32 OptionCount;
276 EFI_DHCP6_PACKET_OPTION *BootFileOpt;
277 EFI_DHCP6_PACKET_OPTION **OptionList;
278 ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData;
279 UINT16 ParaLen;
280
281 OptionCount = 0;
282 BootFileOpt = NULL;
283
284 Status = This->Parse (This, Packet, &OptionCount, NULL);
285 if (Status != EFI_BUFFER_TOO_SMALL) {
286 return EFI_NOT_READY;
287 }
288
289 OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP6_PACKET_OPTION *));
290 if (OptionList == NULL) {
291 return EFI_NOT_READY;
292 }
293
294 Status = This->Parse (This, Packet, &OptionCount, OptionList);
295 if (EFI_ERROR (Status)) {
296 Status = EFI_NOT_READY;
297 goto Exit;
298 }
299
300 ConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *)Context;
301
302 for (Index = 0; Index < OptionCount; Index++) {
303 OptionList[Index]->OpCode = NTOHS (OptionList[Index]->OpCode);
304 OptionList[Index]->OpLen = NTOHS (OptionList[Index]->OpLen);
305
306 //
307 // Get DNS server addresses from this reply packet.
308 //
309 if (OptionList[Index]->OpCode == DHCP6_OPT_DNS_SERVERS) {
310 if (((OptionList[Index]->OpLen & 0xf) != 0) || (OptionList[Index]->OpLen == 0)) {
311 Status = EFI_UNSUPPORTED;
312 goto Exit;
313 }
314
315 //
316 // Primary DNS server address.
317 //
318 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv6_ADDRESS));
319
320 if (OptionList[Index]->OpLen > 16) {
321 //
322 // Secondary DNS server address
323 //
324 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[16], sizeof (EFI_IPv6_ADDRESS));
325 }
326 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_URL) {
327 //
328 // The server sends this option to inform the client about an URL to a boot file.
329 //
330 BootFileOpt = OptionList[Index];
331 } else if (OptionList[Index]->OpCode == DHCP6_OPT_BOOT_FILE_PARAM) {
332 //
333 // The server sends this option to inform the client about DHCP6 server address.
334 //
335 if (OptionList[Index]->OpLen < 18) {
336 Status = EFI_UNSUPPORTED;
337 goto Exit;
338 }
339
340 //
341 // Check param-len 1, should be 16 bytes.
342 //
343 CopyMem (&ParaLen, &OptionList[Index]->Data[0], sizeof (UINT16));
344 if (NTOHS (ParaLen) != 16) {
345 Status = EFI_UNSUPPORTED;
346 goto Exit;
347 }
348
349 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[2], sizeof (EFI_IPv6_ADDRESS));
350 }
351 }
352
353 if (BootFileOpt == NULL) {
354 Status = EFI_UNSUPPORTED;
355 goto Exit;
356 }
357
358 //
359 // Get iSCSI root path from Boot File Uniform Resource Locator (URL) Option
360 //
362 (CHAR8 *)BootFileOpt->Data,
363 BootFileOpt->OpLen,
364 ConfigData
365 );
366
367Exit:
368
369 FreePool (OptionList);
370 return Status;
371}
372
392 IN EFI_HANDLE Image,
393 IN EFI_HANDLE Controller,
395 )
396{
397 EFI_HANDLE Dhcp6Handle;
398 EFI_DHCP6_PROTOCOL *Dhcp6;
399 EFI_STATUS Status;
400 EFI_STATUS TimerStatus;
402 EFI_DHCP6_RETRANSMISSION InfoReqReXmit;
403 EFI_EVENT Timer;
404 EFI_STATUS MediaStatus;
405
406 //
407 // Check media status before doing DHCP.
408 //
409 MediaStatus = EFI_SUCCESS;
410 NetLibDetectMediaWaitTimeout (Controller, ISCSI_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
411 if (MediaStatus != EFI_SUCCESS) {
412 AsciiPrint ("\n Error: Could not detect network connection.\n");
413 return EFI_NO_MEDIA;
414 }
415
416 //
417 // iSCSI will only request target info from DHCPv6 server.
418 //
419 if (!ConfigData->SessionConfigData.TargetInfoFromDhcp) {
420 return EFI_SUCCESS;
421 }
422
423 Dhcp6Handle = NULL;
424 Dhcp6 = NULL;
425 Oro = NULL;
426 Timer = NULL;
427
428 //
429 // Create a DHCP6 child instance and get the protocol.
430 //
431 Status = NetLibCreateServiceChild (
432 Controller,
433 Image,
434 &gEfiDhcp6ServiceBindingProtocolGuid,
435 &Dhcp6Handle
436 );
437 if (EFI_ERROR (Status)) {
438 return Status;
439 }
440
441 Status = gBS->OpenProtocol (
442 Dhcp6Handle,
443 &gEfiDhcp6ProtocolGuid,
444 (VOID **)&Dhcp6,
445 Image,
446 Controller,
447 EFI_OPEN_PROTOCOL_BY_DRIVER
448 );
449 if (EFI_ERROR (Status)) {
450 goto ON_EXIT;
451 }
452
453 Oro = AllocateZeroPool (sizeof (EFI_DHCP6_PACKET_OPTION) + 5);
454 if (Oro == NULL) {
455 Status = EFI_OUT_OF_RESOURCES;
456 goto ON_EXIT;
457 }
458
459 //
460 // Ask the server to reply with DNS and Boot File URL options by info request.
461 // All members in EFI_DHCP6_PACKET_OPTION are in network order.
462 //
463 Oro->OpCode = HTONS (DHCP6_OPT_ORO);
464 Oro->OpLen = HTONS (2 * 3);
465 Oro->Data[1] = DHCP6_OPT_DNS_SERVERS;
466 Oro->Data[3] = DHCP6_OPT_BOOT_FILE_URL;
467 Oro->Data[5] = DHCP6_OPT_BOOT_FILE_PARAM;
468
469 InfoReqReXmit.Irt = 4;
470 InfoReqReXmit.Mrc = 1;
471 InfoReqReXmit.Mrt = 10;
472 InfoReqReXmit.Mrd = 30;
473
474 Status = Dhcp6->InfoRequest (
475 Dhcp6,
476 TRUE,
477 Oro,
478 0,
479 NULL,
480 &InfoReqReXmit,
481 NULL,
483 ConfigData
484 );
485 if (Status == EFI_NO_MAPPING) {
486 Status = gBS->CreateEvent (EVT_TIMER, TPL_CALLBACK, NULL, NULL, &Timer);
487 if (EFI_ERROR (Status)) {
488 goto ON_EXIT;
489 }
490
491 Status = gBS->SetTimer (
492 Timer,
495 );
496
497 if (EFI_ERROR (Status)) {
498 goto ON_EXIT;
499 }
500
501 do {
502 TimerStatus = gBS->CheckEvent (Timer);
503
504 if (!EFI_ERROR (TimerStatus)) {
505 Status = Dhcp6->InfoRequest (
506 Dhcp6,
507 TRUE,
508 Oro,
509 0,
510 NULL,
511 &InfoReqReXmit,
512 NULL,
514 ConfigData
515 );
516 }
517 } while (TimerStatus == EFI_NOT_READY);
518 }
519
520ON_EXIT:
521
522 if (Oro != NULL) {
523 FreePool (Oro);
524 }
525
526 if (Timer != NULL) {
527 gBS->CloseEvent (Timer);
528 }
529
530 if (Dhcp6 != NULL) {
531 gBS->CloseProtocol (
532 Dhcp6Handle,
533 &gEfiDhcp6ProtocolGuid,
534 Image,
535 Controller
536 );
537 }
538
540 Controller,
541 Image,
542 &gEfiDhcp6ServiceBindingProtocolGuid,
543 Dhcp6Handle
544 );
545
546 return Status;
547}
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
UINTN EFIAPI AsciiStrDecimalToUintn(IN CONST CHAR8 *String)
Definition: String.c:1006
RETURN_STATUS EFIAPI AsciiStrCpyS(OUT CHAR8 *Destination, IN UINTN DestMax, IN CONST CHAR8 *Source)
Definition: SafeString.c:1797
INTN EFIAPI CompareMem(IN CONST VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID *EFIAPI AllocateZeroPool(IN UINTN AllocationSize)
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS EFIAPI IScsiDhcp6ParseReply(IN EFI_DHCP6_PROTOCOL *This, IN VOID *Context, IN EFI_DHCP6_PACKET *Packet)
Definition: IScsiDhcp6.c:267
EFI_STATUS IScsiDhcp6ExtractRootPath(IN CHAR8 *RootPath, IN UINT16 Length, IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData)
Definition: IScsiDhcp6.c:28
EFI_STATUS IScsiDoDhcp6(IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData)
Definition: IScsiDhcp6.c:391
#define ISCSI_GET_MAPPING_TIMEOUT
Definition: IScsiImpl.h:76
EFI_STATUS IScsiAsciiStrToIp(IN CHAR8 *Str, IN UINT8 IpMode, OUT EFI_IP_ADDRESS *Ip)
Definition: IScsiMisc.c:248
EFI_STATUS IScsiAsciiStrToLun(IN CHAR8 *Str, OUT UINT8 *Lun)
Definition: IScsiMisc.c:118
EFI_STATUS IScsiNormalizeName(IN OUT CHAR8 *Name, IN UINTN Len)
Definition: IScsiProto.c:2006
#define NULL
Definition: Base.h:319
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
EFI_STATUS EFIAPI NetLibCreateServiceChild(IN EFI_HANDLE Controller, IN EFI_HANDLE Image, IN EFI_GUID *ServiceBindingGuid, IN OUT EFI_HANDLE *ChildHandle)
Definition: DxeNetLib.c:1967
EFI_STATUS EFIAPI NetLibDestroyServiceChild(IN EFI_HANDLE Controller, IN EFI_HANDLE Image, IN EFI_GUID *ServiceBindingGuid, IN EFI_HANDLE ChildHandle)
Definition: DxeNetLib.c:2020
EFI_STATUS EFIAPI NetLibDetectMediaWaitTimeout(IN EFI_HANDLE ServiceHandle, IN UINT64 Timeout, OUT EFI_STATUS *MediaState)
Definition: DxeNetLib.c:2683
VOID *EFIAPI AllocatePool(IN UINTN AllocationSize)
VOID EFIAPI Exit(IN EFI_STATUS Status)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
UINTN EFIAPI AsciiPrint(IN CONST CHAR8 *Format,...)
Definition: UefiLibPrint.c:250
@ TimerRelative
Definition: UefiSpec.h:539