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