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