• 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 - 2016, 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   // Retrieve 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) ||
731           ((Private->Current->SessionConfigData.SubnetMask.Addr[0] != 0) &&
732            !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), NTOHL(*(UINT32*)Private->Current->SessionConfigData.SubnetMask.Addr)))) {
733         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
734         Status = EFI_INVALID_PARAMETER;
735       } else {
736         CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
737       }
738 
739       break;
740 
741     case KEY_SUBNET_MASK:
742       IScsiUnicodeStrToAsciiStr (IfrNvData->SubnetMask, Ip4String);
743       Status = IScsiAsciiStrToIp (Ip4String, &SubnetMask.v4);
744       if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
745         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
746         Status = EFI_INVALID_PARAMETER;
747       } else {
748         CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
749       }
750 
751       break;
752 
753     case KEY_GATE_WAY:
754       IScsiUnicodeStrToAsciiStr (IfrNvData->Gateway, Ip4String);
755       Status = IScsiAsciiStrToIp (Ip4String, &Gateway.v4);
756       if (EFI_ERROR (Status) ||
757           ((Gateway.Addr[0] != 0) &&
758            (Private->Current->SessionConfigData.SubnetMask.Addr[0] != 0) &&
759            !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL(*(UINT32*)Private->Current->SessionConfigData.SubnetMask.Addr)))) {
760         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
761         Status = EFI_INVALID_PARAMETER;
762       } else {
763         CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
764       }
765 
766       break;
767 
768     case KEY_TARGET_IP:
769       IScsiUnicodeStrToAsciiStr (IfrNvData->TargetIp, Ip4String);
770       Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);
771       if (EFI_ERROR (Status) || IP4_IS_LOCAL_BROADCAST (EFI_NTOHL(HostIp.v4)) || IP4_IS_UNSPECIFIED (EFI_NTOHL(HostIp.v4))) {
772         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
773         Status = EFI_INVALID_PARAMETER;
774       } else {
775         CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp.v4, sizeof (HostIp.v4));
776       }
777 
778       break;
779 
780     case KEY_TARGET_NAME:
781       IScsiUnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);
782       Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));
783       if (EFI_ERROR (Status)) {
784         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid iSCSI Name!", NULL);
785       } else {
786         AsciiStrCpyS (Private->Current->SessionConfigData.TargetName, ISCSI_NAME_MAX_SIZE, IScsiName);
787       }
788 
789       break;
790 
791     case KEY_DHCP_ENABLE:
792       if (IfrNvData->InitiatorInfoFromDhcp == 0) {
793         IfrNvData->TargetInfoFromDhcp = 0;
794       }
795 
796       break;
797 
798     case KEY_BOOT_LUN:
799       IScsiUnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);
800       Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);
801       if (EFI_ERROR (Status)) {
802         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid LUN string!", NULL);
803       } else {
804         CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));
805       }
806 
807       break;
808 
809     case KEY_CHAP_NAME:
810       IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPName, Private->Current->AuthConfigData.CHAPName);
811       break;
812 
813     case KEY_CHAP_SECRET:
814       IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPSecret, Private->Current->AuthConfigData.CHAPSecret);
815       break;
816 
817     case KEY_REVERSE_CHAP_NAME:
818       IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPName, Private->Current->AuthConfigData.ReverseCHAPName);
819       break;
820 
821     case KEY_REVERSE_CHAP_SECRET:
822       IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPSecret, Private->Current->AuthConfigData.ReverseCHAPSecret);
823       break;
824 
825     case KEY_CONFIG_ISID:
826       IScsiParseIsIdFromString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);
827       IScsiConvertIsIdToString (IfrNvData->IsId, Private->Current->SessionConfigData.IsId);
828 
829       break;
830 
831     case KEY_SAVE_CHANGES:
832       //
833       // First, update those fields which don't have INTERACTIVE set.
834       //
835       Private->Current->SessionConfigData.Enabled               = IfrNvData->Enabled;
836       Private->Current->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;
837       Private->Current->SessionConfigData.TargetPort            = IfrNvData->TargetPort;
838       if (Private->Current->SessionConfigData.TargetPort == 0) {
839         Private->Current->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;
840       }
841 
842       Private->Current->SessionConfigData.TargetInfoFromDhcp  = IfrNvData->TargetInfoFromDhcp;
843       Private->Current->AuthConfigData.CHAPType               = IfrNvData->CHAPType;
844 
845       //
846       // Only do full parameter validation if iSCSI is enabled on this device.
847       //
848       if (Private->Current->SessionConfigData.Enabled) {
849         //
850         // Validate the address configuration of the Initiator if DHCP isn't
851         // deployed.
852         //
853         if (!Private->Current->SessionConfigData.InitiatorInfoFromDhcp) {
854           CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.LocalIp, sizeof (HostIp.v4));
855           CopyMem (&SubnetMask.v4, &Private->Current->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));
856           CopyMem (&Gateway.v4, &Private->Current->SessionConfigData.Gateway, sizeof (Gateway.v4));
857 
858           if ((Gateway.Addr[0] != 0)) {
859             if (SubnetMask.Addr[0] == 0) {
860               CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Gateway address is set but subnet mask is zero.", NULL);
861               Status = EFI_INVALID_PARAMETER;
862               break;
863             } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {
864               CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Local IP and Gateway are not in the same subnet.", NULL);
865               Status = EFI_INVALID_PARAMETER;
866               break;
867             }
868           }
869         }
870         //
871         // Validate target configuration if DHCP isn't deployed.
872         //
873         if (!Private->Current->SessionConfigData.TargetInfoFromDhcp) {
874           CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.TargetIp, sizeof (HostIp.v4));
875           if (IP4_IS_UNSPECIFIED (NTOHL (HostIp.Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (HostIp.Addr[0]))) {
876             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Target IP is invalid!", NULL);
877             Status = EFI_INVALID_PARAMETER;
878             break;
879           }
880 
881           //
882           // Validate iSCSI target name configuration again:
883           // The format of iSCSI target name is already verified when user input the name;
884           // here we only check the case user does not input the name.
885           //
886           if (Private->Current->SessionConfigData.TargetName[0] == '\0') {
887             CreatePopUp (
888               EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,
889               &Key,
890               L"iSCSI target name is NULL!",
891               NULL
892               );
893             Status = EFI_INVALID_PARAMETER;
894             break;
895           }
896 
897         }
898 
899         if (IfrNvData->CHAPType != ISCSI_CHAP_NONE) {
900           if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {
901             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"CHAP Name or CHAP Secret is invalid!", NULL);
902             Status = EFI_INVALID_PARAMETER;
903             break;
904           }
905 
906           if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&
907               ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))
908               ) {
909             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Reverse CHAP Name or Reverse CHAP Secret is invalid!", NULL);
910             Status = EFI_INVALID_PARAMETER;
911             break;
912           }
913         }
914       }
915 
916       BufferSize = sizeof (Private->Current->SessionConfigData);
917       gRT->SetVariable (
918             Private->Current->MacString,
919             &gEfiIScsiInitiatorNameProtocolGuid,
920             ISCSI_CONFIG_VAR_ATTR,
921             BufferSize,
922             &Private->Current->SessionConfigData
923             );
924 
925       BufferSize = sizeof (Private->Current->AuthConfigData);
926       gRT->SetVariable (
927             Private->Current->MacString,
928             &gIScsiCHAPAuthInfoGuid,
929             ISCSI_CONFIG_VAR_ATTR,
930             BufferSize,
931             &Private->Current->AuthConfigData
932             );
933       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;
934       break;
935 
936     default:
937       break;
938     }
939   }
940 
941   if (!EFI_ERROR (Status)) {
942     //
943     // Pass changed uncommitted data back to Form Browser
944     //
945     HiiSetBrowserData (&gIp4IScsiConfigGuid, mVendorStorageName, sizeof (ISCSI_CONFIG_IFR_NVDATA), (UINT8 *) IfrNvData, NULL);
946   }
947 
948   FreePool (IfrNvData);
949 
950   return Status;
951 }
952 
953 /**
954   Updates the iSCSI configuration form to add/delete an entry for the iSCSI
955   device specified by the Controller.
956 
957   @param[in]  DriverBindingHandle The driverbinding handle.
958   @param[in]  Controller          The controller handle of the iSCSI device.
959   @param[in]  AddForm             Whether to add or delete a form entry.
960 
961   @retval EFI_SUCCESS             The iSCSI configuration form is updated.
962   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
963   @retval Others                  Other errors as indicated.
964 **/
965 EFI_STATUS
IScsiConfigUpdateForm(IN EFI_HANDLE DriverBindingHandle,IN EFI_HANDLE Controller,IN BOOLEAN AddForm)966 IScsiConfigUpdateForm (
967   IN EFI_HANDLE  DriverBindingHandle,
968   IN EFI_HANDLE  Controller,
969   IN BOOLEAN     AddForm
970   )
971 {
972   LIST_ENTRY                  *Entry;
973   ISCSI_CONFIG_FORM_ENTRY     *ConfigFormEntry;
974   BOOLEAN                     EntryExisted;
975   EFI_STATUS                  Status;
976   EFI_MAC_ADDRESS             MacAddress;
977   UINTN                       HwAddressSize;
978   UINT16                      VlanId;
979   CHAR16                      PortString[128];
980   UINT16                      FormIndex;
981   UINTN                       BufferSize;
982   VOID                        *StartOpCodeHandle;
983   VOID                        *EndOpCodeHandle;
984   EFI_IFR_GUID_LABEL          *StartLabel;
985   EFI_IFR_GUID_LABEL          *EndLabel;
986 
987   ConfigFormEntry = NULL;
988   EntryExisted    = FALSE;
989 
990   NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
991     ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
992 
993     if (ConfigFormEntry->Controller == Controller) {
994       EntryExisted = TRUE;
995       break;
996     }
997   }
998 
999   if (AddForm) {
1000     if (EntryExisted) {
1001       return EFI_SUCCESS;
1002     } else {
1003       //
1004       // Add a new form.
1005       //
1006       ConfigFormEntry = (ISCSI_CONFIG_FORM_ENTRY *) AllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY));
1007       if (ConfigFormEntry == NULL) {
1008         return EFI_OUT_OF_RESOURCES;
1009       }
1010 
1011       InitializeListHead (&ConfigFormEntry->Link);
1012       ConfigFormEntry->Controller = Controller;
1013 
1014       //
1015       // Get the MAC address and convert it into the formatted string.
1016       //
1017       Status = NetLibGetMacAddress (Controller, &MacAddress, &HwAddressSize);
1018       ASSERT (Status == EFI_SUCCESS);
1019       VlanId = NetLibGetVlanId (Controller);
1020 
1021       IScsiMacAddrToStr (&MacAddress, (UINT32) HwAddressSize, VlanId, ConfigFormEntry->MacString);
1022 
1023       //
1024       // Get the normal session configuration data.
1025       //
1026       BufferSize = sizeof (ConfigFormEntry->SessionConfigData);
1027       Status = gRT->GetVariable (
1028                       ConfigFormEntry->MacString,
1029                       &gEfiIScsiInitiatorNameProtocolGuid,
1030                       NULL,
1031                       &BufferSize,
1032                       &ConfigFormEntry->SessionConfigData
1033                       );
1034       if (EFI_ERROR (Status)) {
1035         ZeroMem (&ConfigFormEntry->SessionConfigData, sizeof (ConfigFormEntry->SessionConfigData));
1036 
1037         //
1038         // Generate OUI-format ISID based on MAC address.
1039         //
1040         CopyMem (ConfigFormEntry->SessionConfigData.IsId, &MacAddress, 6);
1041         ConfigFormEntry->SessionConfigData.IsId[0] =
1042           (UINT8) (ConfigFormEntry->SessionConfigData.IsId[0] & 0x3F);
1043       }
1044       //
1045       // Get the CHAP authentication configuration data.
1046       //
1047       BufferSize = sizeof (ConfigFormEntry->AuthConfigData);
1048       Status = gRT->GetVariable (
1049                       ConfigFormEntry->MacString,
1050                       &gIScsiCHAPAuthInfoGuid,
1051                       NULL,
1052                       &BufferSize,
1053                       &ConfigFormEntry->AuthConfigData
1054                       );
1055       if (EFI_ERROR (Status)) {
1056         ZeroMem (&ConfigFormEntry->AuthConfigData, sizeof (ConfigFormEntry->AuthConfigData));
1057       }
1058       //
1059       // Compose the Port string and create a new EFI_STRING_ID.
1060       //
1061       UnicodeSPrint (PortString, sizeof (PortString), L"Port %s", ConfigFormEntry->MacString);
1062       ConfigFormEntry->PortTitleToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
1063 
1064       //
1065       // Compose the help string of this port and create a new EFI_STRING_ID.
1066       //
1067       UnicodeSPrint (PortString, sizeof (PortString), L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);
1068       ConfigFormEntry->PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
1069 
1070       InsertTailList (&mIScsiConfigFormList, &ConfigFormEntry->Link);
1071       mNumberOfIScsiDevices++;
1072     }
1073   } else {
1074     ASSERT (EntryExisted);
1075 
1076     mNumberOfIScsiDevices--;
1077     RemoveEntryList (&ConfigFormEntry->Link);
1078     FreePool (ConfigFormEntry);
1079     mCallbackInfo->Current = NULL;
1080   }
1081   //
1082   // Allocate space for creation of Buffer
1083   //
1084 
1085   //
1086   // Init OpCode Handle
1087   //
1088   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
1089   ASSERT (StartOpCodeHandle != NULL);
1090 
1091   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
1092   ASSERT (EndOpCodeHandle != NULL);
1093 
1094   //
1095   // Create Hii Extend Label OpCode as the start opcode
1096   //
1097   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1098   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1099   StartLabel->Number       = DEVICE_ENTRY_LABEL;
1100 
1101   //
1102   // Create Hii Extend Label OpCode as the end opcode
1103   //
1104   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
1105   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
1106   EndLabel->Number       = LABEL_END;
1107 
1108   FormIndex = 0;
1109   NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
1110     ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
1111 
1112     HiiCreateGotoOpCode (
1113       StartOpCodeHandle,                            // Container for dynamic created opcodes
1114       FORMID_DEVICE_FORM,                           // Target Form ID
1115       ConfigFormEntry->PortTitleToken,              // Prompt text
1116       ConfigFormEntry->PortTitleHelpToken,          // Help text
1117       EFI_IFR_FLAG_CALLBACK,                        // Question flag
1118       (UINT16)(KEY_DEVICE_ENTRY_BASE + FormIndex)   // Question ID
1119       );
1120 
1121     FormIndex++;
1122   }
1123 
1124   HiiUpdateForm (
1125     mCallbackInfo->RegisteredHandle,
1126     &gIp4IScsiConfigGuid,
1127     FORMID_MAIN_FORM,
1128     StartOpCodeHandle, // Label DEVICE_ENTRY_LABEL
1129     EndOpCodeHandle    // LABEL_END
1130     );
1131 
1132   HiiFreeOpCodeHandle (StartOpCodeHandle);
1133   HiiFreeOpCodeHandle (EndOpCodeHandle);
1134 
1135   return EFI_SUCCESS;
1136 }
1137 
1138 /**
1139   Initialize the iSCSI configuration form.
1140 
1141   @param[in]  DriverBindingHandle  The iSCSI driverbinding handle.
1142 
1143   @retval EFI_SUCCESS              The iSCSI configuration form is initialized.
1144   @retval EFI_OUT_OF_RESOURCES     Failed to allocate memory.
1145   @retval Others                   Other errors as indicated.
1146 **/
1147 EFI_STATUS
IScsiConfigFormInit(VOID)1148 IScsiConfigFormInit (
1149   VOID
1150   )
1151 {
1152   EFI_STATUS                  Status;
1153   EFI_HII_DATABASE_PROTOCOL   *HiiDatabase;
1154   ISCSI_FORM_CALLBACK_INFO    *CallbackInfo;
1155 
1156   Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);
1157   if (EFI_ERROR (Status)) {
1158     return Status;
1159   }
1160 
1161   CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));
1162   if (CallbackInfo == NULL) {
1163     return EFI_OUT_OF_RESOURCES;
1164   }
1165 
1166   CallbackInfo->Signature   = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
1167   CallbackInfo->HiiDatabase = HiiDatabase;
1168   CallbackInfo->Current     = NULL;
1169 
1170   CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
1171   CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;
1172   CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;
1173 
1174   Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);
1175   if (EFI_ERROR (Status)) {
1176     FreePool(CallbackInfo);
1177     return Status;
1178   }
1179 
1180   //
1181   // Install Device Path Protocol and Config Access protocol to driver handle
1182   //
1183   Status = gBS->InstallMultipleProtocolInterfaces (
1184                   &CallbackInfo->DriverHandle,
1185                   &gEfiDevicePathProtocolGuid,
1186                   &mIScsiHiiVendorDevicePath,
1187                   &gEfiHiiConfigAccessProtocolGuid,
1188                   &CallbackInfo->ConfigAccess,
1189                   NULL
1190                   );
1191   ASSERT_EFI_ERROR (Status);
1192 
1193   //
1194   // Publish our HII data
1195   //
1196   CallbackInfo->RegisteredHandle = HiiAddPackages (
1197                                      &gIp4IScsiConfigGuid,
1198                                      CallbackInfo->DriverHandle,
1199                                      IScsi4DxeStrings,
1200                                      IScsiConfigDxeBin,
1201                                      NULL
1202                                      );
1203   if (CallbackInfo->RegisteredHandle == NULL) {
1204     FreePool(CallbackInfo);
1205     return EFI_OUT_OF_RESOURCES;
1206   }
1207 
1208   mCallbackInfo = CallbackInfo;
1209 
1210   return Status;
1211 }
1212 
1213 /**
1214   Unload the iSCSI configuration form, this includes: delete all the iSCSI
1215   device configuration entries, uninstall the form callback protocol and
1216   free the resources used.
1217 
1218   @param[in]  DriverBindingHandle The iSCSI driverbinding handle.
1219 
1220   @retval EFI_SUCCESS             The iSCSI configuration form is unloaded.
1221   @retval EFI_OUT_OF_RESOURCES    Failed to allocate memory.
1222 **/
1223 EFI_STATUS
IScsiConfigFormUnload(IN EFI_HANDLE DriverBindingHandle)1224 IScsiConfigFormUnload (
1225   IN EFI_HANDLE  DriverBindingHandle
1226   )
1227 {
1228   ISCSI_CONFIG_FORM_ENTRY     *ConfigFormEntry;
1229 
1230   while (!IsListEmpty (&mIScsiConfigFormList)) {
1231     //
1232     // Uninstall the device forms as the iSCSI driver instance may fail to
1233     // control the controller but still install the device configuration form.
1234     // In such case, upon driver unloading, the driver instance's driverbinding.
1235     // stop () won't be called, so we have to take this chance here to uninstall
1236     // the device form.
1237     //
1238     ConfigFormEntry = NET_LIST_USER_STRUCT (mIScsiConfigFormList.ForwardLink, ISCSI_CONFIG_FORM_ENTRY, Link);
1239     IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);
1240   }
1241 
1242   //
1243   // Remove HII package list
1244   //
1245   mCallbackInfo->HiiDatabase->RemovePackageList (
1246                                 mCallbackInfo->HiiDatabase,
1247                                 mCallbackInfo->RegisteredHandle
1248                                 );
1249 
1250   //
1251   // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
1252   //
1253   gBS->UninstallMultipleProtocolInterfaces (
1254          mCallbackInfo->DriverHandle,
1255          &gEfiDevicePathProtocolGuid,
1256          &mIScsiHiiVendorDevicePath,
1257          &gEfiHiiConfigAccessProtocolGuid,
1258          &mCallbackInfo->ConfigAccess,
1259          NULL
1260          );
1261   FreePool (mCallbackInfo);
1262 
1263   return EFI_SUCCESS;
1264 }
1265