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