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