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