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