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