2 Helper functions for configuring or getting the parameters relating to iSCSI.
4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5 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
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.
15 #include "IScsiImpl.h"
17 CHAR16 mVendorStorageName
[] = L
"ISCSI_CONFIG_IFR_NVDATA";
18 BOOLEAN mIScsiDeviceListUpdated
= FALSE
;
19 UINTN mNumberOfIScsiDevices
= 0;
20 ISCSI_FORM_CALLBACK_INFO
*mCallbackInfo
= NULL
;
22 LIST_ENTRY mIScsiConfigFormList
= {
23 &mIScsiConfigFormList
,
27 HII_VENDOR_DEVICE_PATH mIScsiHiiVendorDevicePath
= {
33 (UINT8
) (sizeof (VENDOR_DEVICE_PATH
)),
34 (UINT8
) ((sizeof (VENDOR_DEVICE_PATH
)) >> 8)
41 END_ENTIRE_DEVICE_PATH_SUBTYPE
,
43 (UINT8
) (END_DEVICE_PATH_LENGTH
),
44 (UINT8
) ((END_DEVICE_PATH_LENGTH
) >> 8)
50 Convert the IPv4 address into a dotted string.
52 @param[in] Ip The IPv4 address.
53 @param[out] Str The dotted IP string.
57 IN EFI_IPv4_ADDRESS
*Ip
,
61 UnicodeSPrint ( Str
, 2 * IP4_STR_MAX_SIZE
, L
"%d.%d.%d.%d", Ip
->Addr
[0], Ip
->Addr
[1], Ip
->Addr
[2], Ip
->Addr
[3]);
66 Parse IsId in string format and convert it to binary.
68 @param[in] String The buffer of the string to be parsed.
69 @param[in, out] IsId The buffer to store IsId.
71 @retval EFI_SUCCESS The operation finished successfully.
72 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
76 IScsiParseIsIdFromString (
77 IN CONST CHAR16
*String
,
85 CHAR16 PortString
[ISCSI_NAME_IFR_MAX_SIZE
];
88 if ((String
== NULL
) || (IsId
== NULL
)) {
89 return EFI_INVALID_PARAMETER
;
92 IsIdStr
= (CHAR16
*) String
;
94 if (StrLen (IsIdStr
) != 6) {
97 (UINTN
) sizeof (PortString
),
98 L
"Error! Input is incorrect, please input 6 hex numbers!\n"
102 EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
,
108 return EFI_INVALID_PARAMETER
;
111 for (Index
= 3; Index
< 6; Index
++) {
112 CopyMem (TempStr
, IsIdStr
, sizeof (TempStr
));
116 // Convert the string to IsId. StrHexToUintn stops at the first character
117 // that is not a valid hex character, '\0' here.
119 NodeVal
= StrHexToUintn (TempStr
);
121 IsId
[Index
] = (UINT8
) NodeVal
;
123 IsIdStr
= IsIdStr
+ 2;
130 Convert IsId from binary to string format.
132 @param[out] String The buffer to store the converted string.
133 @param[in] IsId The buffer to store IsId.
135 @retval EFI_SUCCESS The string converted successfully.
136 @retval EFI_INVALID_PARAMETER Any input parameter is invalid.
140 IScsiConvertIsIdToString (
148 if ((String
== NULL
) || (IsId
== NULL
)) {
149 return EFI_INVALID_PARAMETER
;
152 for (Index
= 0; Index
< 6; Index
++) {
153 if (IsId
[Index
] <= 0xF) {
154 Number
= UnicodeSPrint (
156 2 * ISID_CONFIGURABLE_STORAGE
,
161 Number
= UnicodeSPrint (
163 2 * ISID_CONFIGURABLE_STORAGE
,
170 String
= String
+ Number
;
180 Update the list of iSCSI devices the iSCSI driver is controlling.
182 @retval EFI_SUCCESS The callback successfully handled the action.
183 @retval Others Other errors as indicated.
186 IScsiUpdateDeviceList (
191 ISCSI_DEVICE_LIST
*DeviceList
;
197 UINTN LastDeviceIndex
;
198 EFI_MAC_ADDRESS MacAddress
;
201 ISCSI_MAC_INFO
*CurMacInfo
;
202 ISCSI_MAC_INFO TempMacInfo
;
203 CHAR16 MacString
[70];
204 UINTN DeviceListSize
;
207 // Dump all the handles the Managed Network Service Binding Protocol is installed on.
209 Status
= gBS
->LocateHandleBuffer (
211 &gEfiManagedNetworkServiceBindingProtocolGuid
,
216 if (EFI_ERROR (Status
)) {
221 Status
= gRT
->GetVariable (
223 &gIp4IScsiConfigGuid
,
228 if (Status
== EFI_BUFFER_TOO_SMALL
) {
229 DeviceList
= (ISCSI_DEVICE_LIST
*) AllocatePool (DataSize
);
230 ASSERT (DeviceList
!= NULL
);
234 &gIp4IScsiConfigGuid
,
242 for (HandleIndex
= 0; HandleIndex
< NumHandles
; HandleIndex
++) {
243 Status
= NetLibGetMacAddress (Handles
[HandleIndex
], &MacAddress
, &HwAddressSize
);
244 ASSERT (Status
== EFI_SUCCESS
);
245 VlanId
= NetLibGetVlanId (Handles
[HandleIndex
]);
247 for (Index
= LastDeviceIndex
; Index
< DeviceList
->NumDevice
; Index
++) {
248 CurMacInfo
= &DeviceList
->MacInfo
[Index
];
249 if ((CurMacInfo
->Len
== HwAddressSize
) &&
250 (CurMacInfo
->VlanId
== VlanId
) &&
251 (NET_MAC_EQUAL (&CurMacInfo
->Mac
, MacAddress
.Addr
, HwAddressSize
))
254 // The previous configured NIC is still here.
256 if (Index
!= LastDeviceIndex
) {
258 // Swap the current MAC address entry with the one indexed by
261 CopyMem (&TempMacInfo
, CurMacInfo
, sizeof (ISCSI_MAC_INFO
));
262 CopyMem (CurMacInfo
, &DeviceList
->MacInfo
[LastDeviceIndex
], sizeof (ISCSI_MAC_INFO
));
263 CopyMem (&DeviceList
->MacInfo
[LastDeviceIndex
], &TempMacInfo
, sizeof (ISCSI_MAC_INFO
));
270 if (LastDeviceIndex
== DeviceList
->NumDevice
) {
275 for (Index
= LastDeviceIndex
; Index
< DeviceList
->NumDevice
; Index
++) {
277 // delete the variables
279 CurMacInfo
= &DeviceList
->MacInfo
[Index
];
280 IScsiMacAddrToStr (&CurMacInfo
->Mac
, CurMacInfo
->Len
, CurMacInfo
->VlanId
, MacString
);
281 gRT
->SetVariable (MacString
, &gEfiIScsiInitiatorNameProtocolGuid
, 0, 0, NULL
);
282 gRT
->SetVariable (MacString
, &gIScsiCHAPAuthInfoGuid
, 0, 0, NULL
);
285 FreePool (DeviceList
);
286 } else if (Status
!= EFI_NOT_FOUND
) {
291 // Construct the new iSCSI device list.
293 DeviceListSize
= sizeof (ISCSI_DEVICE_LIST
) + (NumHandles
- 1) * sizeof (ISCSI_MAC_INFO
);
294 DeviceList
= (ISCSI_DEVICE_LIST
*) AllocatePool (DeviceListSize
);
295 ASSERT (DeviceList
!= NULL
);
296 DeviceList
->NumDevice
= (UINT8
) NumHandles
;
298 for (Index
= 0; Index
< NumHandles
; Index
++) {
299 NetLibGetMacAddress (Handles
[Index
], &MacAddress
, &HwAddressSize
);
301 CurMacInfo
= &DeviceList
->MacInfo
[Index
];
302 CopyMem (&CurMacInfo
->Mac
, MacAddress
.Addr
, HwAddressSize
);
303 CurMacInfo
->Len
= (UINT8
) HwAddressSize
;
304 CurMacInfo
->VlanId
= NetLibGetVlanId (Handles
[Index
]);
309 &gIp4IScsiConfigGuid
,
310 ISCSI_CONFIG_VAR_ATTR
,
315 FreePool (DeviceList
);
322 Get the iSCSI configuration form entry by the index of the goto opcode actived.
324 @param[in] Index The 0-based index of the goto opcode actived.
326 @return The iSCSI configuration form entry found.
328 ISCSI_CONFIG_FORM_ENTRY
*
329 IScsiGetConfigFormEntryByIndex (
335 ISCSI_CONFIG_FORM_ENTRY
*ConfigFormEntry
;
338 ConfigFormEntry
= NULL
;
340 NET_LIST_FOR_EACH (Entry
, &mIScsiConfigFormList
) {
341 if (CurrentIndex
== Index
) {
342 ConfigFormEntry
= NET_LIST_USER_STRUCT (Entry
, ISCSI_CONFIG_FORM_ENTRY
, Link
);
349 return ConfigFormEntry
;
353 Convert the iSCSI configuration data into the IFR data.
355 @param[in] ConfigFormEntry The iSCSI configuration form entry.
356 @param[out] IfrNvData The IFR nv data.
360 IScsiConvertDeviceConfigDataToIfrNvData (
361 IN ISCSI_CONFIG_FORM_ENTRY
*ConfigFormEntry
,
362 OUT ISCSI_CONFIG_IFR_NVDATA
*IfrNvData
365 ISCSI_SESSION_CONFIG_NVDATA
*SessionConfigData
;
366 ISCSI_CHAP_AUTH_CONFIG_NVDATA
*AuthConfigData
;
369 // Normal session configuration parameters.
371 SessionConfigData
= &ConfigFormEntry
->SessionConfigData
;
372 IfrNvData
->Enabled
= SessionConfigData
->Enabled
;
374 IfrNvData
->InitiatorInfoFromDhcp
= SessionConfigData
->InitiatorInfoFromDhcp
;
375 IfrNvData
->TargetInfoFromDhcp
= SessionConfigData
->TargetInfoFromDhcp
;
376 IfrNvData
->TargetPort
= SessionConfigData
->TargetPort
;
378 IScsiIpToStr (&SessionConfigData
->LocalIp
, IfrNvData
->LocalIp
);
379 IScsiIpToStr (&SessionConfigData
->SubnetMask
, IfrNvData
->SubnetMask
);
380 IScsiIpToStr (&SessionConfigData
->Gateway
, IfrNvData
->Gateway
);
381 IScsiIpToStr (&SessionConfigData
->TargetIp
, IfrNvData
->TargetIp
);
383 IScsiAsciiStrToUnicodeStr (SessionConfigData
->TargetName
, IfrNvData
->TargetName
);
385 IScsiLunToUnicodeStr (SessionConfigData
->BootLun
, IfrNvData
->BootLun
);
387 IScsiConvertIsIdToString (IfrNvData
->IsId
, SessionConfigData
->IsId
);
390 // CHAP authentication parameters.
392 AuthConfigData
= &ConfigFormEntry
->AuthConfigData
;
394 IfrNvData
->CHAPType
= AuthConfigData
->CHAPType
;
396 IScsiAsciiStrToUnicodeStr (AuthConfigData
->CHAPName
, IfrNvData
->CHAPName
);
397 IScsiAsciiStrToUnicodeStr (AuthConfigData
->CHAPSecret
, IfrNvData
->CHAPSecret
);
398 IScsiAsciiStrToUnicodeStr (AuthConfigData
->ReverseCHAPName
, IfrNvData
->ReverseCHAPName
);
399 IScsiAsciiStrToUnicodeStr (AuthConfigData
->ReverseCHAPSecret
, IfrNvData
->ReverseCHAPSecret
);
403 This function allows the caller to request the current
404 configuration for one or more named elements. The resulting
405 string is in <ConfigAltResp> format. Any and all alternative
406 configuration strings shall also be appended to the end of the
407 current configuration string. If they are, they must appear
408 after the current configuration. They must contain the same
409 routing (GUID, NAME, PATH) as the current configuration string.
410 They must have an additional description indicating the type of
411 alternative configuration the string represents,
412 "ALTCFG=<StringToken>". That <StringToken> (when
413 converted from Hex UNICODE to binary) is a reference to a
414 string in the associated string pack.
416 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
417 @param[in] Request A null-terminated Unicode string in
418 <ConfigRequest> format. Note that this
419 includes the routing information as well as
420 the configurable name / value pairs. It is
421 invalid for this string to be in
422 <MultiConfigRequest> format.
423 @param[out] Progress On return, points to a character in the
424 Request string. Points to the string's null
425 terminator if request was successful. Points
426 to the most recent "&" before the first
427 failing name / value pair (or the beginning
428 of the string if the failure is in the first
429 name / value pair) if the request was not
431 @param[out] Results A null-terminated Unicode string in
432 <ConfigAltResp> format which has all values
433 filled in for the names in the Request string.
434 String to be allocated by the called function.
436 @retval EFI_SUCCESS The Results string is filled with the
437 values corresponding to all requested
439 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
440 parts of the results that must be
441 stored awaiting possible future
443 @retval EFI_INVALID_PARAMETER For example, passing in a NULL
444 for the Request parameter
445 would result in this type of
446 error. In this case, the
447 Progress parameter would be
449 @retval EFI_NOT_FOUND Routing data doesn't match any
450 known driver. Progress set to the
451 first character in the routing header.
452 Note: There is no requirement that the
453 driver validate the routing data. It
454 must skip the <ConfigHdr> in order to
456 @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set
457 to most recent & before the
458 error or the beginning of the
460 @retval EFI_INVALID_PARAMETER Unknown name. Progress points
461 to the & before the name in
462 question.Currently not implemented.
466 IScsiFormExtractConfig (
467 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
468 IN CONST EFI_STRING Request
,
469 OUT EFI_STRING
*Progress
,
470 OUT EFI_STRING
*Results
474 CHAR8 InitiatorName
[ISCSI_NAME_MAX_SIZE
];
476 ISCSI_CONFIG_IFR_NVDATA
*IfrNvData
;
477 ISCSI_FORM_CALLBACK_INFO
*Private
;
478 EFI_HII_CONFIG_ROUTING_PROTOCOL
*HiiConfigRouting
;
479 EFI_STRING ConfigRequestHdr
;
480 EFI_STRING ConfigRequest
;
481 BOOLEAN AllocatedRequest
;
484 if (Progress
== NULL
|| Results
== NULL
) {
485 return EFI_INVALID_PARAMETER
;
489 if ((Request
!= NULL
) && !HiiIsConfigHdrMatch (Request
, &gIp4IScsiConfigGuid
, mVendorStorageName
)) {
490 return EFI_NOT_FOUND
;
493 ConfigRequestHdr
= NULL
;
494 ConfigRequest
= NULL
;
495 AllocatedRequest
= FALSE
;
498 if (!mIScsiDeviceListUpdated
) {
500 // Update the device list.
502 IScsiUpdateDeviceList ();
503 mIScsiDeviceListUpdated
= TRUE
;
506 Private
= ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This
);
507 IfrNvData
= AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA
));
508 ASSERT (IfrNvData
!= NULL
);
509 if (Private
->Current
!= NULL
) {
510 IScsiConvertDeviceConfigDataToIfrNvData (Private
->Current
, IfrNvData
);
513 BufferSize
= ISCSI_NAME_MAX_SIZE
;
514 Status
= gIScsiInitiatorName
.Get (&gIScsiInitiatorName
, &BufferSize
, InitiatorName
);
515 if (EFI_ERROR (Status
)) {
516 IfrNvData
->InitiatorName
[0] = L
'\0';
518 IScsiAsciiStrToUnicodeStr (InitiatorName
, IfrNvData
->InitiatorName
);
522 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
524 HiiConfigRouting
= Private
->ConfigRouting
;
525 BufferSize
= sizeof (ISCSI_CONFIG_IFR_NVDATA
);
526 ConfigRequest
= Request
;
527 if ((Request
== NULL
) || (StrStr (Request
, L
"OFFSET") == NULL
)) {
529 // Request has no request element, construct full request string.
530 // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
531 // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
533 ConfigRequestHdr
= HiiConstructConfigHdr (&gIp4IScsiConfigGuid
, mVendorStorageName
, Private
->DriverHandle
);
534 Size
= (StrLen (ConfigRequestHdr
) + 32 + 1) * sizeof (CHAR16
);
535 ConfigRequest
= AllocateZeroPool (Size
);
536 ASSERT (ConfigRequest
!= NULL
);
537 AllocatedRequest
= TRUE
;
538 UnicodeSPrint (ConfigRequest
, Size
, L
"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr
, (UINT64
)BufferSize
);
539 FreePool (ConfigRequestHdr
);
541 Status
= HiiConfigRouting
->BlockToConfig (
549 FreePool (IfrNvData
);
551 // Free the allocated config request string.
553 if (AllocatedRequest
) {
554 FreePool (ConfigRequest
);
555 ConfigRequest
= NULL
;
559 // Set Progress string to the original request string.
561 if (Request
== NULL
) {
563 } else if (StrStr (Request
, L
"OFFSET") == NULL
) {
564 *Progress
= Request
+ StrLen (Request
);
571 This function applies changes in a driver's configuration.
572 Input is a Configuration, which has the routing data for this
573 driver followed by name / value configuration pairs. The driver
574 must apply those pairs to its configurable storage. If the
575 driver's configuration is stored in a linear block of data
576 and the driver's name / value pairs are in <BlockConfig>
577 format, it may use the ConfigToBlock helper function (above) to
578 simplify the job. Currently not implemented.
580 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
581 @param[in] Configuration A null-terminated Unicode string in
582 <ConfigString> format.
583 @param[out] Progress A pointer to a string filled in with the
584 offset of the most recent '&' before the
585 first failing name / value pair (or the
586 beginn ing of the string if the failure
587 is in the first name / value pair) or
588 the terminating NULL if all was
591 @retval EFI_SUCCESS The results have been distributed or are
592 awaiting distribution.
593 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
594 parts of the results that must be
595 stored awaiting possible future
597 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
598 Results parameter would result
599 in this type of error.
600 @retval EFI_NOT_FOUND Target for the specified routing data
605 IScsiFormRouteConfig (
606 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
607 IN CONST EFI_STRING Configuration
,
608 OUT EFI_STRING
*Progress
611 if (Configuration
== NULL
|| Progress
== NULL
) {
612 return EFI_INVALID_PARAMETER
;
616 // Check routing data in <ConfigHdr>.
617 // Note: if only one Storage is used, then this checking could be skipped.
619 if (!HiiIsConfigHdrMatch (Configuration
, &gIp4IScsiConfigGuid
, mVendorStorageName
)) {
620 *Progress
= Configuration
;
621 return EFI_NOT_FOUND
;
624 *Progress
= Configuration
+ StrLen (Configuration
);
629 This function is called to provide results data to the driver.
630 This data consists of a unique key that is used to identify
631 which data is either being passed back or being asked for.
633 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
634 @param[in] Action Specifies the type of action taken by the browser.
635 @param[in] QuestionId A unique value which is sent to the original
636 exporting driver so that it can identify the type
637 of data to expect. The format of the data tends to
638 vary based on the opcode that enerated the callback.
639 @param[in] Type The type of value for the question.
640 @param[in] Value A pointer to the data being sent to the original
642 @param[out] ActionRequest On return, points to the action requested by the
645 @retval EFI_SUCCESS The callback successfully handled the action.
646 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
647 variable and its data.
648 @retval EFI_DEVICE_ERROR The variable could not be saved.
649 @retval EFI_UNSUPPORTED The specified Action is not supported by the
650 callback.Currently not implemented.
651 @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
652 @retval Others Other errors as indicated.
657 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL
*This
,
658 IN EFI_BROWSER_ACTION Action
,
659 IN EFI_QUESTION_ID QuestionId
,
661 IN EFI_IFR_TYPE_VALUE
*Value
,
662 OUT EFI_BROWSER_ACTION_REQUEST
*ActionRequest
665 ISCSI_FORM_CALLBACK_INFO
*Private
;
667 CHAR8 IScsiName
[ISCSI_NAME_MAX_SIZE
];
668 CHAR16 PortString
[128];
669 CHAR8 Ip4String
[IP4_STR_MAX_SIZE
];
670 CHAR8 LunString
[ISCSI_LUN_STR_MAX_LEN
];
672 EFI_STRING_ID DeviceFormTitleToken
;
673 ISCSI_CONFIG_IFR_NVDATA
*IfrNvData
;
674 ISCSI_CONFIG_FORM_ENTRY
*ConfigFormEntry
;
675 EFI_IP_ADDRESS HostIp
;
676 EFI_IP_ADDRESS SubnetMask
;
677 EFI_IP_ADDRESS Gateway
;
681 if (Action
!= EFI_BROWSER_ACTION_CHANGING
&& Action
!= EFI_BROWSER_ACTION_CHANGED
) {
682 return EFI_UNSUPPORTED
;
685 Private
= ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This
);
687 // Retrieve uncommitted data from Browser
689 IfrNvData
= AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA
));
690 ASSERT (IfrNvData
!= NULL
);
691 if (!HiiGetBrowserData (&gIp4IScsiConfigGuid
, mVendorStorageName
, sizeof (ISCSI_CONFIG_IFR_NVDATA
), (UINT8
*) IfrNvData
)) {
692 FreePool (IfrNvData
);
693 return EFI_NOT_FOUND
;
695 Status
= EFI_SUCCESS
;
697 if (Action
== EFI_BROWSER_ACTION_CHANGING
) {
698 if ((QuestionId
>= KEY_DEVICE_ENTRY_BASE
) && (QuestionId
< (mNumberOfIScsiDevices
+ KEY_DEVICE_ENTRY_BASE
))) {
700 // In case goto the device configuration form, update the device form title.
702 ConfigFormEntry
= IScsiGetConfigFormEntryByIndex ((UINT32
) (QuestionId
- KEY_DEVICE_ENTRY_BASE
));
703 ASSERT (ConfigFormEntry
!= NULL
);
705 UnicodeSPrint (PortString
, (UINTN
) sizeof (PortString
), L
"Port %s", ConfigFormEntry
->MacString
);
706 DeviceFormTitleToken
= (EFI_STRING_ID
) STR_ISCSI_DEVICE_FORM_TITLE
;
707 HiiSetString (Private
->RegisteredHandle
, DeviceFormTitleToken
, PortString
, NULL
);
709 IScsiConvertDeviceConfigDataToIfrNvData (ConfigFormEntry
, IfrNvData
);
711 Private
->Current
= ConfigFormEntry
;
713 } else if (Action
== EFI_BROWSER_ACTION_CHANGED
) {
714 switch (QuestionId
) {
715 case KEY_INITIATOR_NAME
:
716 IScsiUnicodeStrToAsciiStr (IfrNvData
->InitiatorName
, IScsiName
);
717 BufferSize
= AsciiStrSize (IScsiName
);
719 Status
= gIScsiInitiatorName
.Set (&gIScsiInitiatorName
, &BufferSize
, IScsiName
);
720 if (EFI_ERROR (Status
)) {
721 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid iSCSI Name!", NULL
);
724 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_APPLY
;
728 IScsiUnicodeStrToAsciiStr (IfrNvData
->LocalIp
, Ip4String
);
729 Status
= IScsiAsciiStrToIp (Ip4String
, &HostIp
.v4
);
730 if (EFI_ERROR (Status
) || !NetIp4IsUnicast (NTOHL (HostIp
.Addr
[0]), 0)) {
731 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid IP address!", NULL
);
732 Status
= EFI_INVALID_PARAMETER
;
734 CopyMem (&Private
->Current
->SessionConfigData
.LocalIp
, &HostIp
.v4
, sizeof (HostIp
.v4
));
739 case KEY_SUBNET_MASK
:
740 IScsiUnicodeStrToAsciiStr (IfrNvData
->SubnetMask
, Ip4String
);
741 Status
= IScsiAsciiStrToIp (Ip4String
, &SubnetMask
.v4
);
742 if (EFI_ERROR (Status
) || ((SubnetMask
.Addr
[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask
.v4
) == 0))) {
743 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid Subnet Mask!", NULL
);
744 Status
= EFI_INVALID_PARAMETER
;
746 CopyMem (&Private
->Current
->SessionConfigData
.SubnetMask
, &SubnetMask
.v4
, sizeof (SubnetMask
.v4
));
752 IScsiUnicodeStrToAsciiStr (IfrNvData
->Gateway
, Ip4String
);
753 Status
= IScsiAsciiStrToIp (Ip4String
, &Gateway
.v4
);
754 if (EFI_ERROR (Status
) || ((Gateway
.Addr
[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway
.Addr
[0]), 0))) {
755 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid Gateway!", NULL
);
756 Status
= EFI_INVALID_PARAMETER
;
758 CopyMem (&Private
->Current
->SessionConfigData
.Gateway
, &Gateway
.v4
, sizeof (Gateway
.v4
));
764 IScsiUnicodeStrToAsciiStr (IfrNvData
->TargetIp
, Ip4String
);
765 Status
= IScsiAsciiStrToIp (Ip4String
, &HostIp
.v4
);
766 if (EFI_ERROR (Status
) || !NetIp4IsUnicast (NTOHL (HostIp
.Addr
[0]), 0)) {
767 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid IP address!", NULL
);
768 Status
= EFI_INVALID_PARAMETER
;
770 CopyMem (&Private
->Current
->SessionConfigData
.TargetIp
, &HostIp
.v4
, sizeof (HostIp
.v4
));
775 case KEY_TARGET_NAME
:
776 IScsiUnicodeStrToAsciiStr (IfrNvData
->TargetName
, IScsiName
);
777 Status
= IScsiNormalizeName (IScsiName
, AsciiStrLen (IScsiName
));
778 if (EFI_ERROR (Status
)) {
779 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid iSCSI Name!", NULL
);
781 AsciiStrCpyS (Private
->Current
->SessionConfigData
.TargetName
, ISCSI_NAME_MAX_SIZE
, IScsiName
);
786 case KEY_DHCP_ENABLE
:
787 if (IfrNvData
->InitiatorInfoFromDhcp
== 0) {
788 IfrNvData
->TargetInfoFromDhcp
= 0;
794 IScsiUnicodeStrToAsciiStr (IfrNvData
->BootLun
, LunString
);
795 Status
= IScsiAsciiStrToLun (LunString
, (UINT8
*) &Lun
);
796 if (EFI_ERROR (Status
)) {
797 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Invalid LUN string!", NULL
);
799 CopyMem (Private
->Current
->SessionConfigData
.BootLun
, &Lun
, sizeof (Lun
));
805 IScsiUnicodeStrToAsciiStr (IfrNvData
->CHAPName
, Private
->Current
->AuthConfigData
.CHAPName
);
808 case KEY_CHAP_SECRET
:
809 IScsiUnicodeStrToAsciiStr (IfrNvData
->CHAPSecret
, Private
->Current
->AuthConfigData
.CHAPSecret
);
812 case KEY_REVERSE_CHAP_NAME
:
813 IScsiUnicodeStrToAsciiStr (IfrNvData
->ReverseCHAPName
, Private
->Current
->AuthConfigData
.ReverseCHAPName
);
816 case KEY_REVERSE_CHAP_SECRET
:
817 IScsiUnicodeStrToAsciiStr (IfrNvData
->ReverseCHAPSecret
, Private
->Current
->AuthConfigData
.ReverseCHAPSecret
);
820 case KEY_CONFIG_ISID
:
821 IScsiParseIsIdFromString (IfrNvData
->IsId
, Private
->Current
->SessionConfigData
.IsId
);
822 IScsiConvertIsIdToString (IfrNvData
->IsId
, Private
->Current
->SessionConfigData
.IsId
);
826 case KEY_SAVE_CHANGES
:
828 // First, update those fields which don't have INTERACTIVE set.
830 Private
->Current
->SessionConfigData
.Enabled
= IfrNvData
->Enabled
;
831 Private
->Current
->SessionConfigData
.InitiatorInfoFromDhcp
= IfrNvData
->InitiatorInfoFromDhcp
;
832 Private
->Current
->SessionConfigData
.TargetPort
= IfrNvData
->TargetPort
;
833 if (Private
->Current
->SessionConfigData
.TargetPort
== 0) {
834 Private
->Current
->SessionConfigData
.TargetPort
= ISCSI_WELL_KNOWN_PORT
;
837 Private
->Current
->SessionConfigData
.TargetInfoFromDhcp
= IfrNvData
->TargetInfoFromDhcp
;
838 Private
->Current
->AuthConfigData
.CHAPType
= IfrNvData
->CHAPType
;
841 // Only do full parameter validation if iSCSI is enabled on this device.
843 if (Private
->Current
->SessionConfigData
.Enabled
) {
845 // Validate the address configuration of the Initiator if DHCP isn't
848 if (!Private
->Current
->SessionConfigData
.InitiatorInfoFromDhcp
) {
849 CopyMem (&HostIp
.v4
, &Private
->Current
->SessionConfigData
.LocalIp
, sizeof (HostIp
.v4
));
850 CopyMem (&SubnetMask
.v4
, &Private
->Current
->SessionConfigData
.SubnetMask
, sizeof (SubnetMask
.v4
));
851 CopyMem (&Gateway
.v4
, &Private
->Current
->SessionConfigData
.Gateway
, sizeof (Gateway
.v4
));
853 if ((Gateway
.Addr
[0] != 0)) {
854 if (SubnetMask
.Addr
[0] == 0) {
855 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Gateway address is set but subnet mask is zero.", NULL
);
856 Status
= EFI_INVALID_PARAMETER
;
858 } else if (!IP4_NET_EQUAL (HostIp
.Addr
[0], Gateway
.Addr
[0], SubnetMask
.Addr
[0])) {
859 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Local IP and Gateway are not in the same subnet.", NULL
);
860 Status
= EFI_INVALID_PARAMETER
;
866 // Validate target configuration if DHCP isn't deployed.
868 if (!Private
->Current
->SessionConfigData
.TargetInfoFromDhcp
) {
869 CopyMem (&HostIp
.v4
, &Private
->Current
->SessionConfigData
.TargetIp
, sizeof (HostIp
.v4
));
870 if (!NetIp4IsUnicast (NTOHL (HostIp
.Addr
[0]), 0)) {
871 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Target IP is invalid!", NULL
);
872 Status
= EFI_INVALID_PARAMETER
;
877 // Validate iSCSI target name configuration again:
878 // The format of iSCSI target name is already verified when user input the name;
879 // here we only check the case user does not input the name.
881 if (Private
->Current
->SessionConfigData
.TargetName
[0] == '\0') {
883 EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
,
885 L
"iSCSI target name is NULL!",
888 Status
= EFI_INVALID_PARAMETER
;
894 if (IfrNvData
->CHAPType
!= ISCSI_CHAP_NONE
) {
895 if ((IfrNvData
->CHAPName
[0] == '\0') || (IfrNvData
->CHAPSecret
[0] == '\0')) {
896 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"CHAP Name or CHAP Secret is invalid!", NULL
);
897 Status
= EFI_INVALID_PARAMETER
;
901 if ((IfrNvData
->CHAPType
== ISCSI_CHAP_MUTUAL
) &&
902 ((IfrNvData
->ReverseCHAPName
[0] == '\0') || (IfrNvData
->ReverseCHAPSecret
[0] == '\0'))
904 CreatePopUp (EFI_LIGHTGRAY
| EFI_BACKGROUND_BLUE
, &Key
, L
"Reverse CHAP Name or Reverse CHAP Secret is invalid!", NULL
);
905 Status
= EFI_INVALID_PARAMETER
;
911 BufferSize
= sizeof (Private
->Current
->SessionConfigData
);
913 Private
->Current
->MacString
,
914 &gEfiIScsiInitiatorNameProtocolGuid
,
915 ISCSI_CONFIG_VAR_ATTR
,
917 &Private
->Current
->SessionConfigData
920 BufferSize
= sizeof (Private
->Current
->AuthConfigData
);
922 Private
->Current
->MacString
,
923 &gIScsiCHAPAuthInfoGuid
,
924 ISCSI_CONFIG_VAR_ATTR
,
926 &Private
->Current
->AuthConfigData
928 *ActionRequest
= EFI_BROWSER_ACTION_REQUEST_FORM_APPLY
;
936 if (!EFI_ERROR (Status
)) {
938 // Pass changed uncommitted data back to Form Browser
940 HiiSetBrowserData (&gIp4IScsiConfigGuid
, mVendorStorageName
, sizeof (ISCSI_CONFIG_IFR_NVDATA
), (UINT8
*) IfrNvData
, NULL
);
943 FreePool (IfrNvData
);
949 Updates the iSCSI configuration form to add/delete an entry for the iSCSI
950 device specified by the Controller.
952 @param[in] DriverBindingHandle The driverbinding handle.
953 @param[in] Controller The controller handle of the iSCSI device.
954 @param[in] AddForm Whether to add or delete a form entry.
956 @retval EFI_SUCCESS The iSCSI configuration form is updated.
957 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
958 @retval Others Other errors as indicated.
961 IScsiConfigUpdateForm (
962 IN EFI_HANDLE DriverBindingHandle
,
963 IN EFI_HANDLE Controller
,
968 ISCSI_CONFIG_FORM_ENTRY
*ConfigFormEntry
;
969 BOOLEAN EntryExisted
;
971 EFI_MAC_ADDRESS MacAddress
;
974 CHAR16 PortString
[128];
977 VOID
*StartOpCodeHandle
;
978 VOID
*EndOpCodeHandle
;
979 EFI_IFR_GUID_LABEL
*StartLabel
;
980 EFI_IFR_GUID_LABEL
*EndLabel
;
982 ConfigFormEntry
= NULL
;
983 EntryExisted
= FALSE
;
985 NET_LIST_FOR_EACH (Entry
, &mIScsiConfigFormList
) {
986 ConfigFormEntry
= NET_LIST_USER_STRUCT (Entry
, ISCSI_CONFIG_FORM_ENTRY
, Link
);
988 if (ConfigFormEntry
->Controller
== Controller
) {
1001 ConfigFormEntry
= (ISCSI_CONFIG_FORM_ENTRY
*) AllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY
));
1002 if (ConfigFormEntry
== NULL
) {
1003 return EFI_OUT_OF_RESOURCES
;
1006 InitializeListHead (&ConfigFormEntry
->Link
);
1007 ConfigFormEntry
->Controller
= Controller
;
1010 // Get the MAC address and convert it into the formatted string.
1012 Status
= NetLibGetMacAddress (Controller
, &MacAddress
, &HwAddressSize
);
1013 ASSERT (Status
== EFI_SUCCESS
);
1014 VlanId
= NetLibGetVlanId (Controller
);
1016 IScsiMacAddrToStr (&MacAddress
, (UINT32
) HwAddressSize
, VlanId
, ConfigFormEntry
->MacString
);
1019 // Get the normal session configuration data.
1021 BufferSize
= sizeof (ConfigFormEntry
->SessionConfigData
);
1022 Status
= gRT
->GetVariable (
1023 ConfigFormEntry
->MacString
,
1024 &gEfiIScsiInitiatorNameProtocolGuid
,
1027 &ConfigFormEntry
->SessionConfigData
1029 if (EFI_ERROR (Status
)) {
1030 ZeroMem (&ConfigFormEntry
->SessionConfigData
, sizeof (ConfigFormEntry
->SessionConfigData
));
1033 // Generate OUI-format ISID based on MAC address.
1035 CopyMem (ConfigFormEntry
->SessionConfigData
.IsId
, &MacAddress
, 6);
1036 ConfigFormEntry
->SessionConfigData
.IsId
[0] =
1037 (UINT8
) (ConfigFormEntry
->SessionConfigData
.IsId
[0] & 0x3F);
1040 // Get the CHAP authentication configuration data.
1042 BufferSize
= sizeof (ConfigFormEntry
->AuthConfigData
);
1043 Status
= gRT
->GetVariable (
1044 ConfigFormEntry
->MacString
,
1045 &gIScsiCHAPAuthInfoGuid
,
1048 &ConfigFormEntry
->AuthConfigData
1050 if (EFI_ERROR (Status
)) {
1051 ZeroMem (&ConfigFormEntry
->AuthConfigData
, sizeof (ConfigFormEntry
->AuthConfigData
));
1054 // Compose the Port string and create a new EFI_STRING_ID.
1056 UnicodeSPrint (PortString
, sizeof (PortString
), L
"Port %s", ConfigFormEntry
->MacString
);
1057 ConfigFormEntry
->PortTitleToken
= HiiSetString (mCallbackInfo
->RegisteredHandle
, 0, PortString
, NULL
);
1060 // Compose the help string of this port and create a new EFI_STRING_ID.
1062 UnicodeSPrint (PortString
, sizeof (PortString
), L
"Set the iSCSI parameters on port %s", ConfigFormEntry
->MacString
);
1063 ConfigFormEntry
->PortTitleHelpToken
= HiiSetString (mCallbackInfo
->RegisteredHandle
, 0, PortString
, NULL
);
1065 InsertTailList (&mIScsiConfigFormList
, &ConfigFormEntry
->Link
);
1066 mNumberOfIScsiDevices
++;
1069 ASSERT (EntryExisted
);
1071 mNumberOfIScsiDevices
--;
1072 RemoveEntryList (&ConfigFormEntry
->Link
);
1073 FreePool (ConfigFormEntry
);
1076 // Allocate space for creation of Buffer
1080 // Init OpCode Handle
1082 StartOpCodeHandle
= HiiAllocateOpCodeHandle ();
1083 ASSERT (StartOpCodeHandle
!= NULL
);
1085 EndOpCodeHandle
= HiiAllocateOpCodeHandle ();
1086 ASSERT (EndOpCodeHandle
!= NULL
);
1089 // Create Hii Extend Label OpCode as the start opcode
1091 StartLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (StartOpCodeHandle
, &gEfiIfrTianoGuid
, NULL
, sizeof (EFI_IFR_GUID_LABEL
));
1092 StartLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
1093 StartLabel
->Number
= DEVICE_ENTRY_LABEL
;
1096 // Create Hii Extend Label OpCode as the end opcode
1098 EndLabel
= (EFI_IFR_GUID_LABEL
*) HiiCreateGuidOpCode (EndOpCodeHandle
, &gEfiIfrTianoGuid
, NULL
, sizeof (EFI_IFR_GUID_LABEL
));
1099 EndLabel
->ExtendOpCode
= EFI_IFR_EXTEND_OP_LABEL
;
1100 EndLabel
->Number
= LABEL_END
;
1103 NET_LIST_FOR_EACH (Entry
, &mIScsiConfigFormList
) {
1104 ConfigFormEntry
= NET_LIST_USER_STRUCT (Entry
, ISCSI_CONFIG_FORM_ENTRY
, Link
);
1106 HiiCreateGotoOpCode (
1107 StartOpCodeHandle
, // Container for dynamic created opcodes
1108 FORMID_DEVICE_FORM
, // Target Form ID
1109 ConfigFormEntry
->PortTitleToken
, // Prompt text
1110 ConfigFormEntry
->PortTitleHelpToken
, // Help text
1111 EFI_IFR_FLAG_CALLBACK
, // Question flag
1112 (UINT16
)(KEY_DEVICE_ENTRY_BASE
+ FormIndex
) // Question ID
1119 mCallbackInfo
->RegisteredHandle
,
1120 &gIp4IScsiConfigGuid
,
1122 StartOpCodeHandle
, // Label DEVICE_ENTRY_LABEL
1123 EndOpCodeHandle
// LABEL_END
1126 HiiFreeOpCodeHandle (StartOpCodeHandle
);
1127 HiiFreeOpCodeHandle (EndOpCodeHandle
);
1133 Initialize the iSCSI configuration form.
1135 @param[in] DriverBindingHandle The iSCSI driverbinding handle.
1137 @retval EFI_SUCCESS The iSCSI configuration form is initialized.
1138 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1139 @retval Others Other errors as indicated.
1142 IScsiConfigFormInit (
1147 EFI_HII_DATABASE_PROTOCOL
*HiiDatabase
;
1148 ISCSI_FORM_CALLBACK_INFO
*CallbackInfo
;
1150 Status
= gBS
->LocateProtocol (&gEfiHiiDatabaseProtocolGuid
, NULL
, (VOID
**)&HiiDatabase
);
1151 if (EFI_ERROR (Status
)) {
1155 CallbackInfo
= (ISCSI_FORM_CALLBACK_INFO
*) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO
));
1156 if (CallbackInfo
== NULL
) {
1157 return EFI_OUT_OF_RESOURCES
;
1160 CallbackInfo
->Signature
= ISCSI_FORM_CALLBACK_INFO_SIGNATURE
;
1161 CallbackInfo
->HiiDatabase
= HiiDatabase
;
1162 CallbackInfo
->Current
= NULL
;
1164 CallbackInfo
->ConfigAccess
.ExtractConfig
= IScsiFormExtractConfig
;
1165 CallbackInfo
->ConfigAccess
.RouteConfig
= IScsiFormRouteConfig
;
1166 CallbackInfo
->ConfigAccess
.Callback
= IScsiFormCallback
;
1168 Status
= gBS
->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid
, NULL
, (VOID
**)&CallbackInfo
->ConfigRouting
);
1169 if (EFI_ERROR (Status
)) {
1170 FreePool(CallbackInfo
);
1175 // Install Device Path Protocol and Config Access protocol to driver handle
1177 Status
= gBS
->InstallMultipleProtocolInterfaces (
1178 &CallbackInfo
->DriverHandle
,
1179 &gEfiDevicePathProtocolGuid
,
1180 &mIScsiHiiVendorDevicePath
,
1181 &gEfiHiiConfigAccessProtocolGuid
,
1182 &CallbackInfo
->ConfigAccess
,
1185 ASSERT_EFI_ERROR (Status
);
1188 // Publish our HII data
1190 CallbackInfo
->RegisteredHandle
= HiiAddPackages (
1191 &gIp4IScsiConfigGuid
,
1192 CallbackInfo
->DriverHandle
,
1197 if (CallbackInfo
->RegisteredHandle
== NULL
) {
1198 FreePool(CallbackInfo
);
1199 return EFI_OUT_OF_RESOURCES
;
1202 mCallbackInfo
= CallbackInfo
;
1208 Unload the iSCSI configuration form, this includes: delete all the iSCSI
1209 device configuration entries, uninstall the form callback protocol and
1210 free the resources used.
1212 @param[in] DriverBindingHandle The iSCSI driverbinding handle.
1214 @retval EFI_SUCCESS The iSCSI configuration form is unloaded.
1215 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1218 IScsiConfigFormUnload (
1219 IN EFI_HANDLE DriverBindingHandle
1222 ISCSI_CONFIG_FORM_ENTRY
*ConfigFormEntry
;
1224 while (!IsListEmpty (&mIScsiConfigFormList
)) {
1226 // Uninstall the device forms as the iSCSI driver instance may fail to
1227 // control the controller but still install the device configuration form.
1228 // In such case, upon driver unloading, the driver instance's driverbinding.
1229 // stop () won't be called, so we have to take this chance here to uninstall
1232 ConfigFormEntry
= NET_LIST_USER_STRUCT (mIScsiConfigFormList
.ForwardLink
, ISCSI_CONFIG_FORM_ENTRY
, Link
);
1233 IScsiConfigUpdateForm (DriverBindingHandle
, ConfigFormEntry
->Controller
, FALSE
);
1237 // Remove HII package list
1239 mCallbackInfo
->HiiDatabase
->RemovePackageList (
1240 mCallbackInfo
->HiiDatabase
,
1241 mCallbackInfo
->RegisteredHandle
1245 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
1247 gBS
->UninstallMultipleProtocolInterfaces (
1248 mCallbackInfo
->DriverHandle
,
1249 &gEfiDevicePathProtocolGuid
,
1250 &mIScsiHiiVendorDevicePath
,
1251 &gEfiHiiConfigAccessProtocolGuid
,
1252 &mCallbackInfo
->ConfigAccess
,
1255 FreePool (mCallbackInfo
);