TianoCore EDK2 master
Loading...
Searching...
No Matches
IScsiDhcp.c
Go to the documentation of this file.
1
9#include "IScsiImpl.h"
10
27 IN CHAR8 *RootPath,
28 IN UINT8 Length,
30 )
31{
32 EFI_STATUS Status;
33 UINT8 IScsiRootPathIdLen;
34 CHAR8 *TmpStr;
35 ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];
37 UINT32 FieldIndex;
38 UINT8 Index;
39 ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData;
41 UINT8 IpMode;
42
43 ConfigNvData = &ConfigData->SessionConfigData;
44
45 //
46 // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
47 //
48 IScsiRootPathIdLen = (UINT8)AsciiStrLen (ISCSI_ROOT_PATH_ID);
49
50 if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {
51 return EFI_NOT_FOUND;
52 }
53
54 //
55 // Skip the iSCSI RootPath ID "iscsi:".
56 //
57 RootPath += IScsiRootPathIdLen;
58 Length = (UINT8)(Length - IScsiRootPathIdLen);
59
60 TmpStr = (CHAR8 *)AllocatePool (Length + 1);
61 if (TmpStr == NULL) {
62 return EFI_OUT_OF_RESOURCES;
63 }
64
65 CopyMem (TmpStr, RootPath, Length);
66 TmpStr[Length] = '\0';
67
68 Index = 0;
69 FieldIndex = RP_FIELD_IDX_SERVERNAME;
70 ZeroMem (&Fields[0], sizeof (Fields));
71
72 //
73 // Extract the fields in the Root Path option string.
74 //
75 for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {
76 if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {
77 Fields[FieldIndex].Str = &TmpStr[Index];
78 }
79
80 while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
81 Index++;
82 }
83
84 if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {
85 if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {
86 TmpStr[Index] = '\0';
87 Index++;
88 }
89
90 if (Fields[FieldIndex].Str != NULL) {
91 Fields[FieldIndex].Len = (UINT8)AsciiStrLen (Fields[FieldIndex].Str);
92 }
93 }
94 }
95
96 if (FieldIndex != RP_FIELD_IDX_MAX) {
97 Status = EFI_INVALID_PARAMETER;
98 goto ON_EXIT;
99 }
100
101 if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||
102 (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||
103 (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)
104 )
105 {
106 Status = EFI_INVALID_PARAMETER;
107 goto ON_EXIT;
108 }
109
110 //
111 // Get the IP address of the target.
112 //
113 Field = &Fields[RP_FIELD_IDX_SERVERNAME];
114
115 if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {
116 IpMode = ConfigNvData->IpMode;
117 } else {
118 IpMode = ConfigData->AutoConfigureMode;
119 }
120
121 //
122 // Server name is expressed as domain name, just save it.
123 //
124 if ((!NET_IS_DIGIT (*(Field->Str))) && (*(Field->Str) != '[')) {
125 ConfigNvData->DnsMode = TRUE;
126 if ((Field->Len + 2) > sizeof (ConfigNvData->TargetUrl)) {
127 return EFI_INVALID_PARAMETER;
128 }
129
130 CopyMem (&ConfigNvData->TargetUrl, Field->Str, Field->Len);
131 ConfigNvData->TargetUrl[Field->Len + 1] = '\0';
132 } else {
133 ConfigNvData->DnsMode = FALSE;
134 ZeroMem (ConfigNvData->TargetUrl, sizeof (ConfigNvData->TargetUrl));
135 Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);
136 CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));
137
138 if (EFI_ERROR (Status)) {
139 goto ON_EXIT;
140 }
141 }
142
143 //
144 // Check the protocol type.
145 //
146 Field = &Fields[RP_FIELD_IDX_PROTOCOL];
147 if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {
148 Status = EFI_INVALID_PARAMETER;
149 goto ON_EXIT;
150 }
151
152 //
153 // Get the port of the iSCSI target.
154 //
155 Field = &Fields[RP_FIELD_IDX_PORT];
156 if (Field->Str != NULL) {
157 ConfigNvData->TargetPort = (UINT16)AsciiStrDecimalToUintn (Field->Str);
158 } else {
159 ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
160 }
161
162 //
163 // Get the LUN.
164 //
165 Field = &Fields[RP_FIELD_IDX_LUN];
166 if (Field->Str != NULL) {
167 Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);
168 if (EFI_ERROR (Status)) {
169 goto ON_EXIT;
170 }
171 } else {
172 ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));
173 }
174
175 //
176 // Get the target iSCSI Name.
177 //
178 Field = &Fields[RP_FIELD_IDX_TARGETNAME];
179
180 if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {
181 Status = EFI_INVALID_PARAMETER;
182 goto ON_EXIT;
183 }
184
185 //
186 // Validate the iSCSI name.
187 //
188 Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));
189 if (EFI_ERROR (Status)) {
190 goto ON_EXIT;
191 }
192
193 AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);
194
195ON_EXIT:
196
197 FreePool (TmpStr);
198
199 return Status;
200}
201
220EFIAPI
223 IN VOID *Context,
224 IN EFI_DHCP4_STATE CurrentState,
225 IN EFI_DHCP4_EVENT Dhcp4Event,
226 IN EFI_DHCP4_PACKET *Packet OPTIONAL,
227 OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL
228 )
229{
230 EFI_STATUS Status;
231 UINT32 OptionCount;
232 EFI_DHCP4_PACKET_OPTION **OptionList;
233 UINT32 Index;
234
235 if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {
236 return EFI_SUCCESS;
237 }
238
239 OptionCount = 0;
240
241 Status = This->Parse (This, Packet, &OptionCount, NULL);
242 if (Status != EFI_BUFFER_TOO_SMALL) {
243 return EFI_NOT_READY;
244 }
245
246 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
247 if (OptionList == NULL) {
248 return EFI_NOT_READY;
249 }
250
251 Status = This->Parse (This, Packet, &OptionCount, OptionList);
252 if (EFI_ERROR (Status)) {
253 FreePool (OptionList);
254 return EFI_NOT_READY;
255 }
256
257 for (Index = 0; Index < OptionCount; Index++) {
258 if (OptionList[Index]->OpCode != DHCP4_TAG_ROOTPATH) {
259 continue;
260 }
261
262 Status = IScsiDhcpExtractRootPath (
263 (CHAR8 *)&OptionList[Index]->Data[0],
264 OptionList[Index]->Length,
266 );
267
268 break;
269 }
270
271 if (Index == OptionCount) {
272 Status = EFI_NOT_READY;
273 }
274
275 FreePool (OptionList);
276
277 return Status;
278}
279
295 IN EFI_DHCP4_PROTOCOL *Dhcp4,
297 )
298{
299 EFI_STATUS Status;
300 EFI_DHCP4_MODE_DATA Dhcp4ModeData;
301 UINT32 OptionCount;
302 EFI_DHCP4_PACKET_OPTION **OptionList;
303 UINT32 Index;
305
306 Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);
307 if (EFI_ERROR (Status)) {
308 return Status;
309 }
310
311 if (Dhcp4ModeData.State != Dhcp4Bound) {
312 return EFI_NO_MAPPING;
313 }
314
315 NvData = &ConfigData->SessionConfigData;
316
317 CopyMem (&NvData->LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
318 CopyMem (&NvData->SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
319 CopyMem (&NvData->Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
320
321 OptionCount = 0;
322 OptionList = NULL;
323
324 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);
325 if (Status != EFI_BUFFER_TOO_SMALL) {
326 return EFI_DEVICE_ERROR;
327 }
328
329 OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
330 if (OptionList == NULL) {
331 return EFI_OUT_OF_RESOURCES;
332 }
333
334 Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);
335 if (EFI_ERROR (Status)) {
336 FreePool (OptionList);
337 return EFI_DEVICE_ERROR;
338 }
339
340 for (Index = 0; Index < OptionCount; Index++) {
341 //
342 // Get DNS server addresses and DHCP server address from this offer.
343 //
344 if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
345 if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
346 Status = EFI_INVALID_PARAMETER;
347 break;
348 }
349
350 //
351 // Primary DNS server address.
352 //
353 CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));
354
355 if (OptionList[Index]->Length > 4) {
356 //
357 // Secondary DNS server address.
358 //
359 CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));
360 }
361 } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {
362 if (OptionList[Index]->Length != 4) {
363 Status = EFI_INVALID_PARAMETER;
364 break;
365 }
366
367 CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));
368 }
369 }
370
371 FreePool (OptionList);
372
373 return Status;
374}
375
387 IN EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2
388 )
389{
391 EFI_STATUS Status;
392 UINTN DataSize;
393
394 DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
395 Status = Ip4Config2->GetData (
396 Ip4Config2,
398 &DataSize,
399 &Policy
400 );
401 if (EFI_ERROR (Status)) {
402 return Status;
403 }
404
405 if (Policy != Ip4Config2PolicyStatic) {
406 Policy = Ip4Config2PolicyStatic;
407 Status = Ip4Config2->SetData (
408 Ip4Config2,
410 sizeof (EFI_IP4_CONFIG2_POLICY),
411 &Policy
412 );
413 if (EFI_ERROR (Status)) {
414 return Status;
415 }
416 }
417
418 return EFI_SUCCESS;
419}
420
436 IN EFI_HANDLE Image,
437 IN EFI_HANDLE Controller,
439 )
440{
441 EFI_HANDLE Dhcp4Handle;
442 EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2;
443 EFI_DHCP4_PROTOCOL *Dhcp4;
444 EFI_STATUS Status;
445 EFI_DHCP4_PACKET_OPTION *ParaList;
446 EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;
448 EFI_STATUS MediaStatus;
449
450 Dhcp4Handle = NULL;
451 Ip4Config2 = NULL;
452 Dhcp4 = NULL;
453 ParaList = NULL;
454
455 //
456 // Check media status before doing DHCP.
457 //
458 MediaStatus = EFI_SUCCESS;
459 NetLibDetectMediaWaitTimeout (Controller, ISCSI_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
460 if (MediaStatus != EFI_SUCCESS) {
461 AsciiPrint ("\n Error: Could not detect network connection.\n");
462 return EFI_NO_MEDIA;
463 }
464
465 //
466 // DHCP4 service allows only one of its children to be configured in
467 // the active state, If the DHCP4 D.O.R.A started by IP4 auto
468 // configuration and has not been completed, the Dhcp4 state machine
469 // will not be in the right state for the iSCSI to start a new round D.O.R.A.
470 // So, we need to switch its policy to static.
471 //
472 Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **)&Ip4Config2);
473 if (!EFI_ERROR (Status)) {
474 Status = IScsiSetIp4Policy (Ip4Config2);
475 if (EFI_ERROR (Status)) {
476 return Status;
477 }
478 }
479
480 //
481 // Create a DHCP4 child instance and get the protocol.
482 //
483 Status = NetLibCreateServiceChild (
484 Controller,
485 Image,
486 &gEfiDhcp4ServiceBindingProtocolGuid,
487 &Dhcp4Handle
488 );
489 if (EFI_ERROR (Status)) {
490 return Status;
491 }
492
493 Status = gBS->OpenProtocol (
494 Dhcp4Handle,
495 &gEfiDhcp4ProtocolGuid,
496 (VOID **)&Dhcp4,
497 Image,
498 Controller,
499 EFI_OPEN_PROTOCOL_BY_DRIVER
500 );
501 if (EFI_ERROR (Status)) {
502 goto ON_EXIT;
503 }
504
505 NvData = &ConfigData->SessionConfigData;
506
507 ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);
508 if (ParaList == NULL) {
509 Status = EFI_OUT_OF_RESOURCES;
510 goto ON_EXIT;
511 }
512
513 //
514 // Ask the server to reply with Netmask, Router, DNS, and RootPath options.
515 //
516 ParaList->OpCode = DHCP4_TAG_PARA_LIST;
517 ParaList->Length = (UINT8)(NvData->TargetInfoFromDhcp ? 4 : 3);
518 ParaList->Data[0] = DHCP4_TAG_NETMASK;
519 ParaList->Data[1] = DHCP4_TAG_ROUTER;
520 ParaList->Data[2] = DHCP4_TAG_DNS_SERVER;
521 ParaList->Data[3] = DHCP4_TAG_ROOTPATH;
522
523 ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));
524 Dhcp4ConfigData.OptionCount = 1;
525 Dhcp4ConfigData.OptionList = &ParaList;
526
527 if (NvData->TargetInfoFromDhcp) {
528 //
529 // Use callback to select an offer that contains target information.
530 //
531 Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;
532 Dhcp4ConfigData.CallbackContext = ConfigData;
533 }
534
535 Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);
536 if (EFI_ERROR (Status)) {
537 goto ON_EXIT;
538 }
539
540 Status = Dhcp4->Start (Dhcp4, NULL);
541 if (EFI_ERROR (Status)) {
542 goto ON_EXIT;
543 }
544
545 //
546 // Parse the ACK to get required information.
547 //
548 Status = IScsiParseDhcpAck (Dhcp4, ConfigData);
549
550ON_EXIT:
551
552 if (ParaList != NULL) {
553 FreePool (ParaList);
554 }
555
556 if (Dhcp4 != NULL) {
557 Dhcp4->Stop (Dhcp4);
558 Dhcp4->Configure (Dhcp4, NULL);
559
560 gBS->CloseProtocol (
561 Dhcp4Handle,
562 &gEfiDhcp4ProtocolGuid,
563 Image,
564 Controller
565 );
566 }
567
569 Controller,
570 Image,
571 &gEfiDhcp4ServiceBindingProtocolGuid,
572 Dhcp4Handle
573 );
574
575 return Status;
576}
UINT64 UINTN
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)
EFI_DHCP4_STATE
Definition: Dhcp4.h:98
@ Dhcp4Bound
Definition: Dhcp4.h:118
EFI_DHCP4_EVENT
Definition: Dhcp4.h:141
@ Dhcp4SelectOffer
Definition: Dhcp4.h:153
@ Dhcp4RcvdOffer
Definition: Dhcp4.h:149
VOID EFIAPI FreePool(IN VOID *Buffer)
EFI_STATUS IScsiDoDhcp(IN EFI_HANDLE Image, IN EFI_HANDLE Controller, IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData)
Definition: IScsiDhcp.c:435
EFI_STATUS IScsiSetIp4Policy(IN EFI_IP4_CONFIG2_PROTOCOL *Ip4Config2)
Definition: IScsiDhcp.c:386
EFI_STATUS IScsiDhcpExtractRootPath(IN CHAR8 *RootPath, IN UINT8 Length, IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData)
Definition: IScsiDhcp.c:26
EFI_STATUS IScsiParseDhcpAck(IN EFI_DHCP4_PROTOCOL *Dhcp4, IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA *ConfigData)
Definition: IScsiDhcp.c:294
EFI_STATUS EFIAPI IScsiDhcpSelectOffer(IN EFI_DHCP4_PROTOCOL *This, IN VOID *Context, IN EFI_DHCP4_STATE CurrentState, IN EFI_DHCP4_EVENT Dhcp4Event, IN EFI_DHCP4_PACKET *Packet OPTIONAL, OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL)
Definition: IScsiDhcp.c:221
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
EFI_IP4_CONFIG2_POLICY
Definition: Ip4Config2.h:127
@ Ip4Config2PolicyStatic
Definition: Ip4Config2.h:135
@ Ip4Config2DataTypePolicy
Definition: Ip4Config2.h:43
#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)
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
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
VOID * CallbackContext
Definition: Dhcp4.h:282
EFI_DHCP4_PACKET_OPTION ** OptionList
Definition: Dhcp4.h:294
UINT32 OptionCount
Definition: Dhcp4.h:286
EFI_DHCP4_CALLBACK Dhcp4Callback
Definition: Dhcp4.h:278
EFI_IPv4_ADDRESS SubnetMask
Definition: Dhcp4.h:327
EFI_DHCP4_STATE State
Definition: Dhcp4.h:301
EFI_IPv4_ADDRESS RouterAddress
Definition: Dhcp4.h:323
EFI_IPv4_ADDRESS ClientAddress
Definition: Dhcp4.h:310
EFI_DHCP4_PACKET * ReplyPacket
Definition: Dhcp4.h:337