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