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