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