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