]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/IScsiDxe/IScsiConfig.c
Sync in bug fix from EDK I:
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiConfig.c
1 /** @file
2 Helper functions for configuring or getting the parameters relating to ISCSI
3
4 Copyright (c) 2004 - 2008, Intel Corporation
5 All rights reserved. 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 Module Name:
14
15 IScsiConfig.c
16
17 Abstract:
18
19 Helper functions for configuring or getting the parameters relating to ISCSI
20
21 **/
22
23 #include "IScsiImpl.h"
24
25 EFI_GUID mVendorGuid = ISCSI_CONFIG_GUID;
26 BOOLEAN mIScsiDeviceListUpdated = FALSE;
27 UINTN mNumberOfIScsiDevices = 0;
28 ISCSI_FORM_CALLBACK_INFO *mCallbackInfo = NULL;
29
30 LIST_ENTRY mIScsiConfigFormList = {
31 &mIScsiConfigFormList,
32 &mIScsiConfigFormList
33 };
34
35 /**
36 Convert the IPv4 address into a dotted string.
37
38 @param Ip[in] The IPv4 address.
39
40 @param Str[out] The dotted IP string.
41
42 @retval None.
43
44 **/
45 VOID
46 IScsiIpToStr (
47 IN EFI_IPv4_ADDRESS *Ip,
48 OUT CHAR16 *Str
49 )
50 {
51 UnicodeSPrint ( Str, 2 * IP4_STR_MAX_SIZE, L"%d.%d.%d.%d", Ip->Addr[0], Ip->Addr[1], Ip->Addr[2], Ip->Addr[3]);
52 }
53
54 /**
55 Pop up an invalid notify which displays the message in Warning.
56
57 @param Warning[in] The warning message.
58
59 @retval None.
60
61 **/
62 VOID
63 PopUpInvalidNotify (
64 IN CHAR16 *Warning
65 )
66 {
67 EFI_INPUT_KEY Key;
68
69 IfrLibCreatePopUp (1, &Key, Warning);
70 }
71
72 /**
73 Update the list of iSCSI devices the iSCSI driver is controlling.
74
75 @param None.
76
77 @retval None.
78
79 **/
80 EFI_STATUS
81 IScsiUpdateDeviceList (
82 VOID
83 )
84 {
85 EFI_STATUS Status;
86 ISCSI_DEVICE_LIST *DeviceList;
87 UINTN DataSize;
88 UINTN NumHandles;
89 EFI_HANDLE *Handles;
90 UINTN HandleIndex;
91 UINTN Index;
92 UINTN LastDeviceIndex;
93 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
94 EFI_SIMPLE_NETWORK_MODE *Mode;
95 ISCSI_MAC_INFO *CurMacInfo;
96 ISCSI_MAC_INFO TempMacInfo;
97 CHAR16 MacString[65];
98 UINTN DeviceListSize;
99
100 //
101 // Dump all the handles the Simple Network Protocol is installed on.
102 //
103 Status = gBS->LocateHandleBuffer (
104 ByProtocol,
105 &gEfiSimpleNetworkProtocolGuid,
106 NULL,
107 &NumHandles,
108 &Handles
109 );
110 if (EFI_ERROR (Status)) {
111 return Status;
112 }
113
114 DataSize = 0;
115 Status = gRT->GetVariable (
116 L"iSCSIDeviceList",
117 &mVendorGuid,
118 NULL,
119 &DataSize,
120 NULL
121 );
122 if (Status == EFI_BUFFER_TOO_SMALL) {
123 DeviceList = (ISCSI_DEVICE_LIST *) AllocatePool (DataSize);
124
125 gRT->GetVariable (
126 L"iSCSIDeviceList",
127 &mVendorGuid,
128 NULL,
129 &DataSize,
130 DeviceList
131 );
132
133 LastDeviceIndex = 0;
134
135 for (HandleIndex = 0; HandleIndex < NumHandles; HandleIndex++) {
136 gBS->HandleProtocol (Handles[HandleIndex], &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
137
138 Mode = Snp->Mode;
139
140 for (Index = LastDeviceIndex; Index < DeviceList->NumDevice; Index++) {
141 CurMacInfo = &DeviceList->MacInfo[Index];
142 if ((CurMacInfo->Len == Mode->HwAddressSize) &&
143 (NET_MAC_EQUAL (&CurMacInfo->Mac, &Mode->PermanentAddress, Mode->HwAddressSize))
144 ) {
145 //
146 // The previous configured NIC is still here.
147 //
148 if (Index != LastDeviceIndex) {
149 //
150 // Swap the current MAC address entry with the one indexed by
151 // LastDeviceIndex.
152 //
153 CopyMem (&TempMacInfo, CurMacInfo, sizeof (ISCSI_MAC_INFO));
154 CopyMem (CurMacInfo, &DeviceList->MacInfo[LastDeviceIndex], sizeof (ISCSI_MAC_INFO));
155 CopyMem (&DeviceList->MacInfo[LastDeviceIndex], &TempMacInfo, sizeof (ISCSI_MAC_INFO));
156 }
157
158 LastDeviceIndex++;
159 }
160 }
161
162 if (LastDeviceIndex == DeviceList->NumDevice) {
163 break;
164 }
165 }
166
167 for (Index = LastDeviceIndex; Index < DeviceList->NumDevice; Index++) {
168 //
169 // delete the variables
170 //
171 CurMacInfo = &DeviceList->MacInfo[Index];
172 IScsiMacAddrToStr (&CurMacInfo->Mac, CurMacInfo->Len, MacString);
173 gRT->SetVariable (MacString, &gEfiIScsiInitiatorNameProtocolGuid, 0, 0, NULL);
174 gRT->SetVariable (MacString, &mIScsiCHAPAuthInfoGuid, 0, 0, NULL);
175 }
176
177 gBS->FreePool (DeviceList);
178 } else if (Status != EFI_NOT_FOUND) {
179 gBS->FreePool (Handles);
180 return Status;
181 }
182 //
183 // Construct the new iSCSI device list.
184 //
185 DeviceListSize = sizeof (ISCSI_DEVICE_LIST) + (NumHandles - 1) * sizeof (ISCSI_MAC_INFO);
186 DeviceList = (ISCSI_DEVICE_LIST *) AllocatePool (DeviceListSize);
187 DeviceList->NumDevice = (UINT8) NumHandles;
188
189 for (Index = 0; Index < NumHandles; Index++) {
190 gBS->HandleProtocol (Handles[Index], &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
191 Mode = Snp->Mode;
192
193 CurMacInfo = &DeviceList->MacInfo[Index];
194 CopyMem (&CurMacInfo->Mac, &Mode->PermanentAddress, Mode->HwAddressSize);
195 CurMacInfo->Len = (UINT8) Mode->HwAddressSize;
196 }
197
198 gRT->SetVariable (
199 L"iSCSIDeviceList",
200 &mVendorGuid,
201 ISCSI_CONFIG_VAR_ATTR,
202 DeviceListSize,
203 DeviceList
204 );
205
206 gBS->FreePool (DeviceList);
207 gBS->FreePool (Handles);
208
209 return Status;
210 }
211
212 /**
213 Get the iSCSI configuration form entry by the index of the goto opcode actived.
214
215 @param Index[in] The 0-based index of the goto opcode actived.
216
217 @retval The iSCSI configuration form entry found.
218
219 **/
220 ISCSI_CONFIG_FORM_ENTRY *
221 IScsiGetConfigFormEntryByIndex (
222 IN UINT32 Index
223 )
224 {
225 UINT32 CurrentIndex;
226 LIST_ENTRY *Entry;
227 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
228
229 CurrentIndex = 0;
230 ConfigFormEntry = NULL;
231
232 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
233 if (CurrentIndex == Index) {
234 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
235 break;
236 }
237
238 CurrentIndex++;
239 }
240
241 return ConfigFormEntry;
242 }
243
244 /**
245 Convert the iSCSI configuration data into the IFR data.
246
247 @param ConfigFormEntry[in] The iSCSI configuration form entry.
248
249 @param IfrNvData[in] The IFR nv data.
250
251 @retval None.
252
253 **/
254 VOID
255 IScsiConvertDeviceConfigDataToIfrNvData (
256 IN ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry,
257 IN ISCSI_CONFIG_IFR_NVDATA *IfrNvData
258 )
259 {
260 ISCSI_SESSION_CONFIG_NVDATA *SessionConfigData;
261 ISCSI_CHAP_AUTH_CONFIG_NVDATA *AuthConfigData;
262
263 //
264 // Normal session configuration parameters.
265 //
266 SessionConfigData = &ConfigFormEntry->SessionConfigData;
267 IfrNvData->Enabled = SessionConfigData->Enabled;
268
269 IfrNvData->InitiatorInfoFromDhcp = SessionConfigData->InitiatorInfoFromDhcp;
270 IfrNvData->TargetInfoFromDhcp = SessionConfigData->TargetInfoFromDhcp;
271 IfrNvData->TargetPort = SessionConfigData->TargetPort;
272
273 IScsiIpToStr (&SessionConfigData->LocalIp, IfrNvData->LocalIp);
274 IScsiIpToStr (&SessionConfigData->SubnetMask, IfrNvData->SubnetMask);
275 IScsiIpToStr (&SessionConfigData->Gateway, IfrNvData->Gateway);
276 IScsiIpToStr (&SessionConfigData->TargetIp, IfrNvData->TargetIp);
277
278 IScsiAsciiStrToUnicodeStr (SessionConfigData->TargetName, IfrNvData->TargetName);
279
280 IScsiLunToUnicodeStr (SessionConfigData->BootLun, IfrNvData->BootLun);
281
282 //
283 // CHAP authentication parameters.
284 //
285 AuthConfigData = &ConfigFormEntry->AuthConfigData;
286
287 IfrNvData->CHAPType = AuthConfigData->CHAPType;
288
289 IScsiAsciiStrToUnicodeStr (AuthConfigData->CHAPName, IfrNvData->CHAPName);
290 IScsiAsciiStrToUnicodeStr (AuthConfigData->CHAPSecret, IfrNvData->CHAPSecret);
291 IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPName, IfrNvData->ReverseCHAPName);
292 IScsiAsciiStrToUnicodeStr (AuthConfigData->ReverseCHAPSecret, IfrNvData->ReverseCHAPSecret);
293 }
294
295 /**
296 This function allows a caller to extract the current configuration for one
297 or more named elements from the target driver.
298
299 @param This[in] Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
300
301 @param Request[in] A null-terminated Unicode string in <ConfigRequest> format.
302
303 @param Progress[out] On return, points to a character in the Request string.
304 Points to the string's null terminator if request was successful.
305 Points to the most recent '&' before the first failing name/value
306 pair (or the beginning of the string if the failure is in the
307 first name/value pair) if the request was not successful.
308
309 @param Results[out] A null-terminated Unicode string in <ConfigAltResp> format which
310 has all values filled in for the names in the Request string.
311 String to be allocated by the called function.
312
313 @retval EFI_SUCCESS The Results is filled with the requested values.
314
315 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
316
317 @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name.
318
319 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
320
321 **/
322 EFI_STATUS
323 EFIAPI
324 IScsiFormExtractConfig (
325 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
326 IN CONST EFI_STRING Request,
327 OUT EFI_STRING *Progress,
328 OUT EFI_STRING *Results
329 )
330 {
331 EFI_STATUS Status;
332 CHAR8 InitiatorName[ISCSI_NAME_IFR_MAX_SIZE];
333 UINTN BufferSize;
334 ISCSI_CONFIG_IFR_NVDATA *IfrNvData;
335 ISCSI_FORM_CALLBACK_INFO *Private;
336 EFI_HII_CONFIG_ROUTING_PROTOCOL *HiiConfigRouting;
337
338 if (Request == NULL) {
339 return EFI_NOT_FOUND;
340 }
341
342 if (!mIScsiDeviceListUpdated) {
343 //
344 // Update the device list.
345 //
346 IScsiUpdateDeviceList ();
347 mIScsiDeviceListUpdated = TRUE;
348 }
349
350 Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
351 IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
352 ASSERT (IfrNvData != NULL);
353 if (Private->Current != NULL) {
354 IScsiConvertDeviceConfigDataToIfrNvData (Private->Current, IfrNvData);
355 }
356
357 BufferSize = ISCSI_NAME_IFR_MAX_SIZE;
358 Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);
359 if (EFI_ERROR (Status)) {
360 IfrNvData->InitiatorName[0] = L'\0';
361 } else {
362 IScsiAsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);
363 }
364
365 //
366 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
367 //
368 HiiConfigRouting = Private->ConfigRouting;
369 BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
370 Status = HiiConfigRouting->BlockToConfig (
371 HiiConfigRouting,
372 Request,
373 (UINT8 *) IfrNvData,
374 BufferSize,
375 Results,
376 Progress
377 );
378 gBS->FreePool (IfrNvData);
379 return Status;
380 }
381
382 /**
383 This function processes the results of changes in configuration.
384
385 @param This[in] Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
386
387 @param Configuration[in] A null-terminated Unicode string in <ConfigResp> format.
388
389 @param Progress[out] A pointer to a string filled in with the offset of the most
390 recent '&' before the first failing name/value pair (or the
391 beginning of the string if the failure is in the first
392 name/value pair) or the terminating NULL if all was successful.
393
394 @retval EFI_SUCCESS The Results is processed successfully.
395
396 @retval EFI_INVALID_PARAMETER Configuration is NULL.
397
398 @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
399
400 **/
401 EFI_STATUS
402 EFIAPI
403 IScsiFormRouteConfig (
404 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
405 IN CONST EFI_STRING Configuration,
406 OUT EFI_STRING *Progress
407 )
408 {
409 return EFI_SUCCESS;
410 }
411
412 /**
413 This function processes the results of changes in configuration.
414
415 @param This[in] Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
416
417 @param Action[in] Specifies the type of action taken by the browser.
418
419 @param QuestionId[in] A unique value which is sent to the original exporting driver
420 so that it can identify the type of data to expect.
421
422 @param Type[in] The type of value for the question.
423
424 @param Value[in] A pointer to the data being sent to the original exporting driver.
425
426 @param ActionRequest[out] On return, points to the action requested by the callback function.
427
428 @retval EFI_SUCCESS The callback successfully handled the action.
429
430 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
431
432 @retval EFI_DEVICE_ERROR The variable could not be saved.
433
434 @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
435
436 **/
437 EFI_STATUS
438 EFIAPI
439 IScsiFormCallback (
440 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
441 IN EFI_BROWSER_ACTION Action,
442 IN EFI_QUESTION_ID KeyValue,
443 IN UINT8 Type,
444 IN EFI_IFR_TYPE_VALUE *Value,
445 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
446 )
447 {
448 ISCSI_FORM_CALLBACK_INFO *Private;
449 UINTN BufferSize;
450 CHAR8 IScsiName[ISCSI_NAME_IFR_MAX_SIZE];
451 CHAR16 PortString[128];
452 CHAR8 Ip4String[IP4_STR_MAX_SIZE];
453 CHAR8 LunString[ISCSI_LUN_STR_MAX_LEN];
454 UINT64 Lun;
455 EFI_STRING_ID DeviceFormTitleToken;
456 ISCSI_CONFIG_IFR_NVDATA *IfrNvData;
457 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
458 EFI_IP_ADDRESS HostIp;
459 EFI_IP_ADDRESS SubnetMask;
460 EFI_IP_ADDRESS Gateway;
461 EFI_STATUS Status;
462
463 Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
464
465 //
466 // Retrive uncommitted data from Browser
467 //
468 BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
469 IfrNvData = AllocateZeroPool (BufferSize);
470 ASSERT (IfrNvData != NULL);
471 Status = GetBrowserData (NULL, NULL, &BufferSize, (UINT8 *) IfrNvData);
472 if (EFI_ERROR (Status)) {
473 gBS->FreePool (IfrNvData);
474 return Status;
475 }
476
477 switch (KeyValue) {
478 case KEY_INITIATOR_NAME:
479 IScsiUnicodeStrToAsciiStr (IfrNvData->InitiatorName, IScsiName);
480 BufferSize = AsciiStrLen (IScsiName) + 1;
481
482 Status = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);
483 if (EFI_ERROR (Status)) {
484 PopUpInvalidNotify (L"Invalid iSCSI Name!");
485 }
486
487 break;
488
489 case KEY_LOCAL_IP:
490 IScsiUnicodeStrToAsciiStr (IfrNvData->LocalIp, Ip4String);
491 Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);
492 if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
493 PopUpInvalidNotify (L"Invalid IP address!");
494 Status = EFI_INVALID_PARAMETER;
495 } else {
496 CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
497 }
498
499 break;
500
501 case KEY_SUBNET_MASK:
502 IScsiUnicodeStrToAsciiStr (IfrNvData->SubnetMask, Ip4String);
503 Status = IScsiAsciiStrToIp (Ip4String, &SubnetMask.v4);
504 if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
505 PopUpInvalidNotify (L"Invalid Subnet Mask!");
506 Status = EFI_INVALID_PARAMETER;
507 } else {
508 CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
509 }
510
511 break;
512
513 case KEY_GATE_WAY:
514 IScsiUnicodeStrToAsciiStr (IfrNvData->Gateway, Ip4String);
515 Status = IScsiAsciiStrToIp (Ip4String, &Gateway.v4);
516 if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !Ip4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {
517 PopUpInvalidNotify (L"Invalid Gateway!");
518 Status = EFI_INVALID_PARAMETER;
519 } else {
520 CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
521 }
522
523 break;
524
525 case KEY_TARGET_IP:
526 IScsiUnicodeStrToAsciiStr (IfrNvData->TargetIp, Ip4String);
527 Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);
528 if (EFI_ERROR (Status) || !Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
529 PopUpInvalidNotify (L"Invalid IP address!");
530 Status = EFI_INVALID_PARAMETER;
531 } else {
532 CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp.v4, sizeof (HostIp.v4));
533 }
534
535 break;
536
537 case KEY_TARGET_NAME:
538 IScsiUnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);
539 Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));
540 if (EFI_ERROR (Status)) {
541 PopUpInvalidNotify (L"Invalid iSCSI Name!");
542 } else {
543 AsciiStrCpy (Private->Current->SessionConfigData.TargetName, IScsiName);
544 }
545
546 break;
547
548 case KEY_DHCP_ENABLE:
549 if (IfrNvData->InitiatorInfoFromDhcp == 0) {
550 IfrNvData->TargetInfoFromDhcp = 0;
551 }
552
553 break;
554
555 case KEY_BOOT_LUN:
556 IScsiUnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);
557 Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);
558 if (EFI_ERROR (Status)) {
559 PopUpInvalidNotify (L"Invalid LUN string!");
560 } else {
561 CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));
562 }
563
564 break;
565
566 case KEY_CHAP_NAME:
567 IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPName, Private->Current->AuthConfigData.CHAPName);
568 break;
569
570 case KEY_CHAP_SECRET:
571 IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPSecret, Private->Current->AuthConfigData.CHAPSecret);
572 break;
573
574 case KEY_REVERSE_CHAP_NAME:
575 IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPName, Private->Current->AuthConfigData.ReverseCHAPName);
576 break;
577
578 case KEY_REVERSE_CHAP_SECRET:
579 IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPSecret, Private->Current->AuthConfigData.ReverseCHAPSecret);
580 break;
581
582 case KEY_SAVE_CHANGES:
583 //
584 // First, update those fields which don't have INTERACTIVE set.
585 //
586 Private->Current->SessionConfigData.Enabled = IfrNvData->Enabled;
587 Private->Current->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;
588 Private->Current->SessionConfigData.TargetPort = IfrNvData->TargetPort;
589 if (Private->Current->SessionConfigData.TargetPort == 0) {
590 Private->Current->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;
591 }
592
593 Private->Current->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp;
594 Private->Current->AuthConfigData.CHAPType = IfrNvData->CHAPType;
595
596 //
597 // Only do full parameter validation if iSCSI is enabled on this device.
598 //
599 if (Private->Current->SessionConfigData.Enabled) {
600 //
601 // Validate the address configuration of the Initiator if DHCP isn't
602 // deployed.
603 //
604 if (!Private->Current->SessionConfigData.InitiatorInfoFromDhcp) {
605 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.LocalIp, sizeof (HostIp.v4));
606 CopyMem (&SubnetMask.v4, &Private->Current->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));
607 CopyMem (&Gateway.v4, &Private->Current->SessionConfigData.Gateway, sizeof (Gateway.v4));
608
609 if ((Gateway.Addr[0] != 0)) {
610 if (SubnetMask.Addr[0] == 0) {
611 PopUpInvalidNotify (L"Gateway address is set but subnet mask is zero.");
612 Status = EFI_INVALID_PARAMETER;
613 break;
614 } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {
615 PopUpInvalidNotify (L"Local IP and Gateway are not in the same subnet.");
616 Status = EFI_INVALID_PARAMETER;
617 break;
618 }
619 }
620 }
621 //
622 // Validate target configuration if DHCP isn't deployed.
623 //
624 if (!Private->Current->SessionConfigData.TargetInfoFromDhcp) {
625 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.TargetIp, sizeof (HostIp.v4));
626 if (!Ip4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
627 PopUpInvalidNotify (L"Target IP is invalid!");
628 Status = EFI_INVALID_PARAMETER;
629 break;
630 }
631 }
632
633 if (IfrNvData->CHAPType != ISCSI_CHAP_NONE) {
634 if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {
635 PopUpInvalidNotify (L"CHAP Name or CHAP Secret is invalid!");
636 Status = EFI_INVALID_PARAMETER;
637 break;
638 }
639
640 if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&
641 ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))
642 ) {
643 PopUpInvalidNotify (L"Reverse CHAP Name or Reverse CHAP Secret is invalid!");
644 Status = EFI_INVALID_PARAMETER;
645 break;
646 }
647 }
648 }
649
650 BufferSize = sizeof (Private->Current->SessionConfigData);
651 gRT->SetVariable (
652 Private->Current->MacString,
653 &gEfiIScsiInitiatorNameProtocolGuid,
654 ISCSI_CONFIG_VAR_ATTR,
655 BufferSize,
656 &Private->Current->SessionConfigData
657 );
658
659 BufferSize = sizeof (Private->Current->AuthConfigData);
660 gRT->SetVariable (
661 Private->Current->MacString,
662 &mIScsiCHAPAuthInfoGuid,
663 ISCSI_CONFIG_VAR_ATTR,
664 BufferSize,
665 &Private->Current->AuthConfigData
666 );
667 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
668 break;
669
670 default:
671 if ((KeyValue >= KEY_DEVICE_ENTRY_BASE) && (KeyValue < (mNumberOfIScsiDevices + KEY_DEVICE_ENTRY_BASE))) {
672 //
673 // In case goto the device configuration form, update the device form title.
674 //
675 ConfigFormEntry = IScsiGetConfigFormEntryByIndex ((UINT32) (KeyValue - KEY_DEVICE_ENTRY_BASE));
676 ASSERT (ConfigFormEntry != NULL);
677
678 UnicodeSPrint (PortString, (UINTN) 128, L"Port %s", ConfigFormEntry->MacString);
679 DeviceFormTitleToken = (EFI_STRING_ID) STR_ISCSI_DEVICE_FORM_TITLE;
680 HiiLibSetString (Private->RegisteredHandle, DeviceFormTitleToken, PortString);
681
682 IScsiConvertDeviceConfigDataToIfrNvData (ConfigFormEntry, IfrNvData);
683
684 Private->Current = ConfigFormEntry;
685 }
686
687 break;
688 }
689
690 if (!EFI_ERROR (Status)) {
691 //
692 // Pass changed uncommitted data back to Form Browser
693 //
694 BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
695 Status = SetBrowserData (NULL, NULL, BufferSize, (UINT8 *) IfrNvData, NULL);
696 }
697
698 gBS->FreePool (IfrNvData);
699 return Status;
700 }
701
702 /**
703 Updates the iSCSI configuration form to add/delete an entry for the iSCSI
704 device specified by the Controller.
705
706 @param DriverBindingHandle[in] The driverbinding handle.
707
708 @param Controller[in] The controller handle of the iSCSI device.
709
710 @param AddForm[in] Whether to add or delete a form entry.
711
712 @retval EFI_SUCCESS The iSCSI configuration form is updated.
713
714 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
715
716 **/
717 EFI_STATUS
718 IScsiConfigUpdateForm (
719 IN EFI_HANDLE DriverBindingHandle,
720 IN EFI_HANDLE Controller,
721 IN BOOLEAN AddForm
722 )
723 {
724 LIST_ENTRY *Entry;
725 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
726 BOOLEAN EntryExisted;
727 EFI_STATUS Status;
728 EFI_HII_UPDATE_DATA UpdateData;
729 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
730 CHAR16 PortString[128];
731 UINT16 FormIndex;
732 UINTN BufferSize;
733
734
735 ConfigFormEntry = NULL;
736 EntryExisted = FALSE;
737
738 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
739 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
740
741 if (ConfigFormEntry->Controller == Controller) {
742 EntryExisted = TRUE;
743 break;
744 }
745 }
746
747 if (AddForm) {
748 if (EntryExisted) {
749 return EFI_SUCCESS;
750 } else {
751 //
752 // Add a new form.
753 //
754 ConfigFormEntry = (ISCSI_CONFIG_FORM_ENTRY *) AllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY));
755 if (ConfigFormEntry == NULL) {
756 return EFI_OUT_OF_RESOURCES;
757 }
758
759 InitializeListHead (&ConfigFormEntry->Link);
760 ConfigFormEntry->Controller = Controller;
761
762 //
763 // Get the simple network protocol and convert the MAC address into
764 // the formatted string.
765 //
766 Status = gBS->HandleProtocol (
767 Controller,
768 &gEfiSimpleNetworkProtocolGuid,
769 (VOID **)&Snp
770 );
771 ASSERT (Status == EFI_SUCCESS);
772
773 IScsiMacAddrToStr (&Snp->Mode->PermanentAddress, Snp->Mode->HwAddressSize, ConfigFormEntry->MacString);
774
775 //
776 // Get the normal session configuration data.
777 //
778 BufferSize = sizeof (ConfigFormEntry->SessionConfigData);
779 Status = gRT->GetVariable (
780 ConfigFormEntry->MacString,
781 &gEfiIScsiInitiatorNameProtocolGuid,
782 NULL,
783 &BufferSize,
784 &ConfigFormEntry->SessionConfigData
785 );
786 if (EFI_ERROR (Status)) {
787 ZeroMem (&ConfigFormEntry->SessionConfigData, sizeof (ConfigFormEntry->SessionConfigData));
788 }
789 //
790 // Get the CHAP authentication configuration data.
791 //
792 BufferSize = sizeof (ConfigFormEntry->AuthConfigData);
793 Status = gRT->GetVariable (
794 ConfigFormEntry->MacString,
795 &mIScsiCHAPAuthInfoGuid,
796 NULL,
797 &BufferSize,
798 &ConfigFormEntry->AuthConfigData
799 );
800 if (EFI_ERROR (Status)) {
801 ZeroMem (&ConfigFormEntry->AuthConfigData, sizeof (ConfigFormEntry->AuthConfigData));
802 }
803 //
804 // Compose the Port string and create a new EFI_STRING_ID.
805 //
806 UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);
807 HiiLibNewString (mCallbackInfo->RegisteredHandle, &ConfigFormEntry->PortTitleToken, PortString);
808
809 //
810 // Compose the help string of this port and create a new EFI_STRING_ID.
811 //
812 UnicodeSPrint (PortString, 128, L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);
813 HiiLibNewString (mCallbackInfo->RegisteredHandle, &ConfigFormEntry->PortTitleHelpToken, PortString);
814
815 InsertTailList (&mIScsiConfigFormList, &ConfigFormEntry->Link);
816 mNumberOfIScsiDevices++;
817 }
818 } else {
819 ASSERT (EntryExisted);
820
821 mNumberOfIScsiDevices--;
822 RemoveEntryList (&ConfigFormEntry->Link);
823 gBS->FreePool (ConfigFormEntry);
824 }
825 //
826 // Allocate space for creation of Buffer
827 //
828 UpdateData.BufferSize = 0x1000;
829 UpdateData.Data = AllocateZeroPool (0x1000);
830 UpdateData.Offset = 0;
831
832 FormIndex = 0;
833 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
834 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
835
836 CreateGotoOpCode (
837 FORMID_DEVICE_FORM,
838 ConfigFormEntry->PortTitleToken,
839 ConfigFormEntry->PortTitleHelpToken,
840 EFI_IFR_FLAG_CALLBACK,
841 (UINT16)(KEY_DEVICE_ENTRY_BASE + FormIndex),
842 &UpdateData
843 );
844
845 FormIndex++;
846 }
847
848 IfrLibUpdateForm (
849 mCallbackInfo->RegisteredHandle,
850 &mVendorGuid,
851 FORMID_MAIN_FORM,
852 DEVICE_ENTRY_LABEL,
853 FALSE,
854 &UpdateData
855 );
856
857 gBS->FreePool (UpdateData.Data);
858
859 return EFI_SUCCESS;
860 }
861
862 /**
863 Initialize the iSCSI configuration form.
864
865 @param DriverBindingHandle[in] The iSCSI driverbinding handle.
866
867 @retval EFI_SUCCESS The iSCSI configuration form is initialized.
868
869 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
870
871 **/
872 EFI_STATUS
873 IScsiConfigFormInit (
874 IN EFI_HANDLE DriverBindingHandle
875 )
876 {
877 EFI_STATUS Status;
878 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
879 EFI_HII_PACKAGE_LIST_HEADER *PackageList;
880 ISCSI_FORM_CALLBACK_INFO *CallbackInfo;
881
882 Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);
883 if (EFI_ERROR (Status)) {
884 return Status;
885 }
886
887 CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocatePool (sizeof (ISCSI_FORM_CALLBACK_INFO));
888 if (CallbackInfo == NULL) {
889 return EFI_OUT_OF_RESOURCES;
890 }
891
892 CallbackInfo->Signature = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
893 CallbackInfo->HiiDatabase = HiiDatabase;
894 CallbackInfo->Current = NULL;
895
896 CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
897 CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;
898 CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;
899
900 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);
901 if (EFI_ERROR (Status)) {
902 FreePool(CallbackInfo);
903 return Status;
904 }
905
906 //
907 // Create driver handle used by HII database
908 //
909 Status = HiiLibCreateHiiDriverHandle (&CallbackInfo->DriverHandle);
910 if (EFI_ERROR (Status)) {
911 FreePool(CallbackInfo);
912 return Status;
913 }
914
915 //
916 // Install Config Access protocol to driver handle
917 //
918 Status = gBS->InstallProtocolInterface (
919 &CallbackInfo->DriverHandle,
920 &gEfiHiiConfigAccessProtocolGuid,
921 EFI_NATIVE_INTERFACE,
922 &CallbackInfo->ConfigAccess
923 );
924 ASSERT_EFI_ERROR (Status);
925
926 //
927 // Publish our HII data
928 //
929 PackageList = HiiLibPreparePackageList (2, &mVendorGuid, IScsiDxeStrings, IScsiConfigDxeBin);
930 ASSERT (PackageList != NULL);
931
932 Status = HiiDatabase->NewPackageList (
933 HiiDatabase,
934 PackageList,
935 CallbackInfo->DriverHandle,
936 &CallbackInfo->RegisteredHandle
937 );
938 FreePool (PackageList);
939 if (EFI_ERROR (Status)) {
940 FreePool(CallbackInfo);
941 return Status;
942 }
943
944 mCallbackInfo = CallbackInfo;
945
946 return Status;
947 }
948
949 /**
950 Unload the iSCSI configuration form, this includes: delete all the iSCSI
951 device configuration entries, uninstall the form callback protocol and
952 free the resources used.
953
954 @param DriverBindingHandle[in] The iSCSI driverbinding handle.
955
956 @retval EFI_SUCCESS The iSCSI configuration form is unloaded.
957
958 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
959
960 **/
961 EFI_STATUS
962 IScsiConfigFormUnload (
963 IN EFI_HANDLE DriverBindingHandle
964 )
965 {
966 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
967
968 while (!IsListEmpty (&mIScsiConfigFormList)) {
969 //
970 // Uninstall the device forms as the iSCSI driver instance may fail to
971 // control the controller but still install the device configuration form.
972 // In such case, upon driver unloading, the driver instance's driverbinding.
973 // stop () won't be called, so we have to take this chance here to uninstall
974 // the device form.
975 //
976 ConfigFormEntry = NET_LIST_USER_STRUCT (mIScsiConfigFormList.ForwardLink, ISCSI_CONFIG_FORM_ENTRY, Link);
977 IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);
978 }
979
980 //
981 // Remove HII package list
982 //
983 mCallbackInfo->HiiDatabase->RemovePackageList (
984 mCallbackInfo->HiiDatabase,
985 mCallbackInfo->RegisteredHandle
986 );
987
988 //
989 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
990 //
991 gBS->UninstallProtocolInterface (
992 mCallbackInfo->DriverHandle,
993 &gEfiHiiConfigAccessProtocolGuid,
994 &mCallbackInfo->ConfigAccess
995 );
996 HiiLibDestroyHiiDriverHandle (mCallbackInfo->DriverHandle);
997
998 gBS->FreePool (mCallbackInfo);
999
1000 return EFI_SUCCESS;
1001 }