• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Helper functions for configuring or getting the parameters relating to iSCSI.
3 
4 Copyright (c) 2004 - 2015, 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
IScsiIpToStr(IN EFI_IPv4_ADDRESS * Ip,OUT CHAR16 * Str)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
IScsiParseIsIdFromString(IN CONST CHAR16 * String,IN OUT UINT8 * IsId)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
IScsiConvertIsIdToString(OUT CHAR16 * String,IN UINT8 * IsId)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
IScsiUpdateDeviceList(VOID)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 *
IScsiGetConfigFormEntryByIndex(IN UINT32 Index)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
IScsiConvertDeviceConfigDataToIfrNvData(IN ISCSI_CONFIG_FORM_ENTRY * ConfigFormEntry,OUT ISCSI_CONFIG_IFR_NVDATA * IfrNvData)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
IScsiFormExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)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
IScsiFormRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)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
IScsiFormCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)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         AsciiStrCpyS (Private->Current->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, 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           // Validate iSCSI target name configuration again:
878           // The format of iSCSI target name is already verified when user input the name;
879           // here we only check the case user does not input the name.
880           //
881           if (Private->Current->SessionConfigData.TargetName[0] == '\0') {
882             CreatePopUp (
883               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
884               &Key,
885               L"iSCSI target name is NULL!",
886               NULL
887               );
888             Status = EFI_INVALID_PARAMETER;
889             break;
890           }
891 
892         }
893 
894         if (IfrNvData->CHAPType != ISCSI_CHAP_NONE) {
895           if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {
896             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"CHAP Name or CHAP Secret is invalid!", NULL);
897             Status = EFI_INVALID_PARAMETER;
898             break;
899           }
900 
901           if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&
902               ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))
903               ) {
904             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Reverse CHAP Name or Reverse CHAP Secret is invalid!", NULL);
905             Status = EFI_INVALID_PARAMETER;
906             break;
907           }
908         }
909       }
910 
911       BufferSize = sizeof (Private->Current->SessionConfigData);
912       gRT->SetVariable (
913             Private->Current->MacString,
914             &gEfiIScsiInitiatorNameProtocolGuid,
915             ISCSI_CONFIG_VAR_ATTR,
916             BufferSize,
917             &Private->Current->SessionConfigData
918             );
919 
920       BufferSize = sizeof (Private->Current->AuthConfigData);
921       gRT->SetVariable (
922             Private->Current->MacString,
923             &gIScsiCHAPAuthInfoGuid,
924             ISCSI_CONFIG_VAR_ATTR,
925             BufferSize,
926             &Private->Current->AuthConfigData
927             );
928       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
929       break;
930 
931     default:
932       break;
933     }
934   }
935 
936   if (!EFI_ERROR (Status)) {
937     //
938     // Pass changed uncommitted data back to Form Browser
939     //
940     HiiSetBrowserData (&gIp4IScsiConfigGuid, mVendorStorageName, sizeof (ISCSI_CONFIG_IFR_NVDATA), (UINT8 *) IfrNvData, NULL);
941   }
942 
943   FreePool (IfrNvData);
944 
945   return Status;
946 }
947 
948 /**
949   Updates the iSCSI configuration form to add/delete an entry for the iSCSI
950   device specified by the Controller.
951 
952   @param[in]  DriverBindingHandle The driverbinding handle.
953   @param[in]  Controller          The controller handle of the iSCSI device.
954   @param[in]  AddForm             Whether to add or delete a form entry.
955 
956   @retval EFI_SUCCESS             The iSCSI configuration form is updated.
957   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
958   @retval Others                  Other errors as indicated.
959 **/
960 EFI_STATUS
IScsiConfigUpdateForm(IN EFI_HANDLE DriverBindingHandle,IN EFI_HANDLE Controller,IN BOOLEAN AddForm)961 IScsiConfigUpdateForm (
962   IN EFI_HANDLE  DriverBindingHandle,
963   IN EFI_HANDLE  Controller,
964   IN BOOLEAN     AddForm
965   )
966 {
967   LIST_ENTRY                  *Entry;
968   ISCSI_CONFIG_FORM_ENTRY     *ConfigFormEntry;
969   BOOLEAN                     EntryExisted;
970   EFI_STATUS                  Status;
971   EFI_MAC_ADDRESS             MacAddress;
972   UINTN                       HwAddressSize;
973   UINT16                      VlanId;
974   CHAR16                      PortString[128];
975   UINT16                      FormIndex;
976   UINTN                       BufferSize;
977   VOID                        *StartOpCodeHandle;
978   VOID                        *EndOpCodeHandle;
979   EFI_IFR_GUID_LABEL          *StartLabel;
980   EFI_IFR_GUID_LABEL          *EndLabel;
981 
982   ConfigFormEntry = NULL;
983   EntryExisted    = FALSE;
984 
985   NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
986     ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
987 
988     if (ConfigFormEntry->Controller == Controller) {
989       EntryExisted = TRUE;
990       break;
991     }
992   }
993 
994   if (AddForm) {
995     if (EntryExisted) {
996       return EFI_SUCCESS;
997     } else {
998       //
999       // Add a new form.
1000       //
1001       ConfigFormEntry = (ISCSI_CONFIG_FORM_ENTRY *) AllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY));
1002       if (ConfigFormEntry == NULL) {
1003         return EFI_OUT_OF_RESOURCES;
1004       }
1005 
1006       InitializeListHead (&ConfigFormEntry->Link);
1007       ConfigFormEntry->Controller = Controller;
1008 
1009       //
1010       // Get the MAC address and convert it into the formatted string.
1011       //
1012       Status = NetLibGetMacAddress (Controller, &MacAddress, &HwAddressSize);
1013       ASSERT (Status == EFI_SUCCESS);
1014       VlanId = NetLibGetVlanId (Controller);
1015 
1016       IScsiMacAddrToStr (&MacAddress, (UINT32) HwAddressSize, VlanId, ConfigFormEntry->MacString);
1017 
1018       //
1019       // Get the normal session configuration data.
1020       //
1021       BufferSize = sizeof (ConfigFormEntry->SessionConfigData);
1022       Status = gRT->GetVariable (
1023                       ConfigFormEntry->MacString,
1024                       &gEfiIScsiInitiatorNameProtocolGuid,
1025                       NULL,
1026                       &BufferSize,
1027                       &ConfigFormEntry->SessionConfigData
1028                       );
1029       if (EFI_ERROR (Status)) {
1030         ZeroMem (&ConfigFormEntry->SessionConfigData, sizeof (ConfigFormEntry->SessionConfigData));
1031 
1032         //
1033         // Generate OUI-format ISID based on MAC address.
1034         //
1035         CopyMem (ConfigFormEntry->SessionConfigData.IsId, &MacAddress, 6);
1036         ConfigFormEntry->SessionConfigData.IsId[0] =
1037           (UINT8) (ConfigFormEntry->SessionConfigData.IsId[0] & 0x3F);
1038       }
1039       //
1040       // Get the CHAP authentication configuration data.
1041       //
1042       BufferSize = sizeof (ConfigFormEntry->AuthConfigData);
1043       Status = gRT->GetVariable (
1044                       ConfigFormEntry->MacString,
1045                       &gIScsiCHAPAuthInfoGuid,
1046                       NULL,
1047                       &BufferSize,
1048                       &ConfigFormEntry->AuthConfigData
1049                       );
1050       if (EFI_ERROR (Status)) {
1051         ZeroMem (&ConfigFormEntry->AuthConfigData, sizeof (ConfigFormEntry->AuthConfigData));
1052       }
1053       //
1054       // Compose the Port string and create a new EFI_STRING_ID.
1055       //
1056       UnicodeSPrint (PortString, sizeof (PortString), L"Port %s", ConfigFormEntry->MacString);
1057       ConfigFormEntry->PortTitleToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
1058 
1059       //
1060       // Compose the help string of this port and create a new EFI_STRING_ID.
1061       //
1062       UnicodeSPrint (PortString, sizeof (PortString), L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);
1063       ConfigFormEntry->PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
1064 
1065       InsertTailList (&mIScsiConfigFormList, &ConfigFormEntry->Link);
1066       mNumberOfIScsiDevices++;
1067     }
1068   } else {
1069     ASSERT (EntryExisted);
1070 
1071     mNumberOfIScsiDevices--;
1072     RemoveEntryList (&ConfigFormEntry->Link);
1073     FreePool (ConfigFormEntry);
1074   }
1075   //
1076   // Allocate space for creation of Buffer
1077   //
1078 
1079   //
1080   // Init OpCode Handle
1081   //
1082   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1083   ASSERT (StartOpCodeHandle != NULL);
1084 
1085   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1086   ASSERT (EndOpCodeHandle != NULL);
1087 
1088   //
1089   // Create Hii Extend Label OpCode as the start opcode
1090   //
1091   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1092   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1093   StartLabel->Number       = DEVICE_ENTRY_LABEL;
1094 
1095   //
1096   // Create Hii Extend Label OpCode as the end opcode
1097   //
1098   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1099   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1100   EndLabel->Number       = LABEL_END;
1101 
1102   FormIndex = 0;
1103   NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
1104     ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
1105 
1106     HiiCreateGotoOpCode (
1107       StartOpCodeHandle,                            // Container for dynamic created opcodes
1108       FORMID_DEVICE_FORM,                           // Target Form ID
1109       ConfigFormEntry->PortTitleToken,              // Prompt text
1110       ConfigFormEntry->PortTitleHelpToken,          // Help text
1111       EFI_IFR_FLAG_CALLBACK,                        // Question flag
1112       (UINT16)(KEY_DEVICE_ENTRY_BASE + FormIndex)   // Question ID
1113       );
1114 
1115     FormIndex++;
1116   }
1117 
1118   HiiUpdateForm (
1119     mCallbackInfo->RegisteredHandle,
1120     &gIp4IScsiConfigGuid,
1121     FORMID_MAIN_FORM,
1122     StartOpCodeHandle, // Label DEVICE_ENTRY_LABEL
1123     EndOpCodeHandle    // LABEL_END
1124     );
1125 
1126   HiiFreeOpCodeHandle (StartOpCodeHandle);
1127   HiiFreeOpCodeHandle (EndOpCodeHandle);
1128 
1129   return EFI_SUCCESS;
1130 }
1131 
1132 /**
1133   Initialize the iSCSI configuration form.
1134 
1135   @param[in]  DriverBindingHandle  The iSCSI driverbinding handle.
1136 
1137   @retval EFI_SUCCESS              The iSCSI configuration form is initialized.
1138   @retval EFI_OUT_OF_RESOURCES     Failed to allocate memory.
1139   @retval Others                   Other errors as indicated.
1140 **/
1141 EFI_STATUS
IScsiConfigFormInit(VOID)1142 IScsiConfigFormInit (
1143   VOID
1144   )
1145 {
1146   EFI_STATUS                  Status;
1147   EFI_HII_DATABASE_PROTOCOL   *HiiDatabase;
1148   ISCSI_FORM_CALLBACK_INFO    *CallbackInfo;
1149 
1150   Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);
1151   if (EFI_ERROR (Status)) {
1152     return Status;
1153   }
1154 
1155   CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));
1156   if (CallbackInfo == NULL) {
1157     return EFI_OUT_OF_RESOURCES;
1158   }
1159 
1160   CallbackInfo->Signature   = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
1161   CallbackInfo->HiiDatabase = HiiDatabase;
1162   CallbackInfo->Current     = NULL;
1163 
1164   CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
1165   CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;
1166   CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;
1167 
1168   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);
1169   if (EFI_ERROR (Status)) {
1170     FreePool(CallbackInfo);
1171     return Status;
1172   }
1173 
1174   //
1175   // Install Device Path Protocol and Config Access protocol to driver handle
1176   //
1177   Status = gBS->InstallMultipleProtocolInterfaces (
1178                   &CallbackInfo->DriverHandle,
1179                   &gEfiDevicePathProtocolGuid,
1180                   &mIScsiHiiVendorDevicePath,
1181                   &gEfiHiiConfigAccessProtocolGuid,
1182                   &CallbackInfo->ConfigAccess,
1183                   NULL
1184                   );
1185   ASSERT_EFI_ERROR (Status);
1186 
1187   //
1188   // Publish our HII data
1189   //
1190   CallbackInfo->RegisteredHandle = HiiAddPackages (
1191                                      &gIp4IScsiConfigGuid,
1192                                      CallbackInfo->DriverHandle,
1193                                      IScsi4DxeStrings,
1194                                      IScsiConfigDxeBin,
1195                                      NULL
1196                                      );
1197   if (CallbackInfo->RegisteredHandle == NULL) {
1198     FreePool(CallbackInfo);
1199     return EFI_OUT_OF_RESOURCES;
1200   }
1201 
1202   mCallbackInfo = CallbackInfo;
1203 
1204   return Status;
1205 }
1206 
1207 /**
1208   Unload the iSCSI configuration form, this includes: delete all the iSCSI
1209   device configuration entries, uninstall the form callback protocol and
1210   free the resources used.
1211 
1212   @param[in]  DriverBindingHandle The iSCSI driverbinding handle.
1213 
1214   @retval EFI_SUCCESS             The iSCSI configuration form is unloaded.
1215   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
1216 **/
1217 EFI_STATUS
IScsiConfigFormUnload(IN EFI_HANDLE DriverBindingHandle)1218 IScsiConfigFormUnload (
1219   IN EFI_HANDLE  DriverBindingHandle
1220   )
1221 {
1222   ISCSI_CONFIG_FORM_ENTRY     *ConfigFormEntry;
1223 
1224   while (!IsListEmpty (&mIScsiConfigFormList)) {
1225     //
1226     // Uninstall the device forms as the iSCSI driver instance may fail to
1227     // control the controller but still install the device configuration form.
1228     // In such case, upon driver unloading, the driver instance's driverbinding.
1229     // stop () won't be called, so we have to take this chance here to uninstall
1230     // the device form.
1231     //
1232     ConfigFormEntry = NET_LIST_USER_STRUCT (mIScsiConfigFormList.ForwardLink, ISCSI_CONFIG_FORM_ENTRY, Link);
1233     IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);
1234   }
1235 
1236   //
1237   // Remove HII package list
1238   //
1239   mCallbackInfo->HiiDatabase->RemovePackageList (
1240                                 mCallbackInfo->HiiDatabase,
1241                                 mCallbackInfo->RegisteredHandle
1242                                 );
1243 
1244   //
1245   // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
1246   //
1247   gBS->UninstallMultipleProtocolInterfaces (
1248          mCallbackInfo->DriverHandle,
1249          &gEfiDevicePathProtocolGuid,
1250          &mIScsiHiiVendorDevicePath,
1251          &gEfiHiiConfigAccessProtocolGuid,
1252          &mCallbackInfo->ConfigAccess,
1253          NULL
1254          );
1255   FreePool (mCallbackInfo);
1256 
1257   return EFI_SUCCESS;
1258 }
1259