]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Network/IScsiDxe/IScsiConfig.c
Add VLAN support.
[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 - 2009, Intel Corporation.<BR>
5 All rights reserved. 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
364 if (Request == NULL || Progress == NULL || Results == NULL) {
365 return EFI_INVALID_PARAMETER;
366 }
367 *Progress = Request;
368
369 if (!mIScsiDeviceListUpdated) {
370 //
371 // Update the device list.
372 //
373 IScsiUpdateDeviceList ();
374 mIScsiDeviceListUpdated = TRUE;
375 }
376
377 Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
378 IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
379 ASSERT (IfrNvData != NULL);
380 if (Private->Current != NULL) {
381 IScsiConvertDeviceConfigDataToIfrNvData (Private->Current, IfrNvData);
382 }
383
384 BufferSize = ISCSI_NAME_IFR_MAX_SIZE;
385 Status = gIScsiInitiatorName.Get (&gIScsiInitiatorName, &BufferSize, InitiatorName);
386 if (EFI_ERROR (Status)) {
387 IfrNvData->InitiatorName[0] = L'\0';
388 } else {
389 IScsiAsciiStrToUnicodeStr (InitiatorName, IfrNvData->InitiatorName);
390 }
391
392 //
393 // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
394 //
395 HiiConfigRouting = Private->ConfigRouting;
396 BufferSize = sizeof (ISCSI_CONFIG_IFR_NVDATA);
397 Status = HiiConfigRouting->BlockToConfig (
398 HiiConfigRouting,
399 Request,
400 (UINT8 *) IfrNvData,
401 BufferSize,
402 Results,
403 Progress
404 );
405 FreePool (IfrNvData);
406 return Status;
407 }
408
409 /**
410 This function applies changes in a driver's configuration.
411 Input is a Configuration, which has the routing data for this
412 driver followed by name / value configuration pairs. The driver
413 must apply those pairs to its configurable storage. If the
414 driver's configuration is stored in a linear block of data
415 and the driver's name / value pairs are in <BlockConfig>
416 format, it may use the ConfigToBlock helper function (above) to
417 simplify the job. Currently not implemented.
418
419 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
420 @param[in] Configuration A null-terminated Unicode string in
421 <ConfigString> format.
422 @param[out] Progress A pointer to a string filled in with the
423 offset of the most recent '&' before the
424 first failing name / value pair (or the
425 beginn ing of the string if the failure
426 is in the first name / value pair) or
427 the terminating NULL if all was
428 successful.
429
430 @retval EFI_SUCCESS The results have been distributed or are
431 awaiting distribution.
432 @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
433 parts of the results that must be
434 stored awaiting possible future
435 protocols.
436 @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
437 Results parameter would result
438 in this type of error.
439 @retval EFI_NOT_FOUND Target for the specified routing data
440 was not found.
441 **/
442 EFI_STATUS
443 EFIAPI
444 IScsiFormRouteConfig (
445 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
446 IN CONST EFI_STRING Configuration,
447 OUT EFI_STRING *Progress
448 )
449 {
450 if (Configuration == NULL || Progress == NULL) {
451 return EFI_INVALID_PARAMETER;
452 }
453
454 //
455 // Check routing data in <ConfigHdr>.
456 // Note: if only one Storage is used, then this checking could be skipped.
457 //
458 if (!HiiIsConfigHdrMatch (Configuration, &mVendorGuid, mVendorStorageName)) {
459 *Progress = Configuration;
460 return EFI_NOT_FOUND;
461 }
462
463 *Progress = Configuration + StrLen (Configuration);
464 return EFI_SUCCESS;
465 }
466
467 /**
468 This function is called to provide results data to the driver.
469 This data consists of a unique key that is used to identify
470 which data is either being passed back or being asked for.
471
472 @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
473 @param[in] Action Specifies the type of action taken by the browser.
474 @param[in] QuestionId A unique value which is sent to the original
475 exporting driver so that it can identify the type
476 of data to expect. The format of the data tends to
477 vary based on the opcode that enerated the callback.
478 @param[in] Type The type of value for the question.
479 @param[in] Value A pointer to the data being sent to the original
480 exporting driver.
481 @param[out] ActionRequest On return, points to the action requested by the
482 callback function.
483
484 @retval EFI_SUCCESS The callback successfully handled the action.
485 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the
486 variable and its data.
487 @retval EFI_DEVICE_ERROR The variable could not be saved.
488 @retval EFI_UNSUPPORTED The specified Action is not supported by the
489 callback.Currently not implemented.
490 @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
491 @retval Others Other errors as indicated.
492 **/
493 EFI_STATUS
494 EFIAPI
495 IScsiFormCallback (
496 IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
497 IN EFI_BROWSER_ACTION Action,
498 IN EFI_QUESTION_ID QuestionId,
499 IN UINT8 Type,
500 IN EFI_IFR_TYPE_VALUE *Value,
501 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
502 )
503 {
504 ISCSI_FORM_CALLBACK_INFO *Private;
505 UINTN BufferSize;
506 CHAR8 IScsiName[ISCSI_NAME_IFR_MAX_SIZE];
507 CHAR16 PortString[128];
508 CHAR8 Ip4String[IP4_STR_MAX_SIZE];
509 CHAR8 LunString[ISCSI_LUN_STR_MAX_LEN];
510 UINT64 Lun;
511 EFI_STRING_ID DeviceFormTitleToken;
512 ISCSI_CONFIG_IFR_NVDATA *IfrNvData;
513 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
514 EFI_IP_ADDRESS HostIp;
515 EFI_IP_ADDRESS SubnetMask;
516 EFI_IP_ADDRESS Gateway;
517 EFI_STATUS Status;
518 EFI_INPUT_KEY Key;
519
520 Private = ISCSI_FORM_CALLBACK_INFO_FROM_FORM_CALLBACK (This);
521
522 //
523 // Retrive uncommitted data from Browser
524 //
525 IfrNvData = AllocateZeroPool (sizeof (ISCSI_CONFIG_IFR_NVDATA));
526 ASSERT (IfrNvData != NULL);
527 if (!HiiGetBrowserData (&mVendorGuid, mVendorStorageName, sizeof (ISCSI_CONFIG_IFR_NVDATA), (UINT8 *) IfrNvData)) {
528 FreePool (IfrNvData);
529 return EFI_NOT_FOUND;
530 }
531
532 Status = EFI_SUCCESS;
533
534 switch (QuestionId) {
535 case KEY_INITIATOR_NAME:
536 IScsiUnicodeStrToAsciiStr (IfrNvData->InitiatorName, IScsiName);
537 BufferSize = AsciiStrLen (IScsiName) + 1;
538
539 Status = gIScsiInitiatorName.Set (&gIScsiInitiatorName, &BufferSize, IScsiName);
540 if (EFI_ERROR (Status)) {
541 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid iSCSI Name!", NULL);
542 }
543
544 break;
545
546 case KEY_LOCAL_IP:
547 IScsiUnicodeStrToAsciiStr (IfrNvData->LocalIp, Ip4String);
548 Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);
549 if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
550 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
551 Status = EFI_INVALID_PARAMETER;
552 } else {
553 CopyMem (&Private->Current->SessionConfigData.LocalIp, &HostIp.v4, sizeof (HostIp.v4));
554 }
555
556 break;
557
558 case KEY_SUBNET_MASK:
559 IScsiUnicodeStrToAsciiStr (IfrNvData->SubnetMask, Ip4String);
560 Status = IScsiAsciiStrToIp (Ip4String, &SubnetMask.v4);
561 if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (IScsiGetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
562 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
563 Status = EFI_INVALID_PARAMETER;
564 } else {
565 CopyMem (&Private->Current->SessionConfigData.SubnetMask, &SubnetMask.v4, sizeof (SubnetMask.v4));
566 }
567
568 break;
569
570 case KEY_GATE_WAY:
571 IScsiUnicodeStrToAsciiStr (IfrNvData->Gateway, Ip4String);
572 Status = IScsiAsciiStrToIp (Ip4String, &Gateway.v4);
573 if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), 0))) {
574 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
575 Status = EFI_INVALID_PARAMETER;
576 } else {
577 CopyMem (&Private->Current->SessionConfigData.Gateway, &Gateway.v4, sizeof (Gateway.v4));
578 }
579
580 break;
581
582 case KEY_TARGET_IP:
583 IScsiUnicodeStrToAsciiStr (IfrNvData->TargetIp, Ip4String);
584 Status = IScsiAsciiStrToIp (Ip4String, &HostIp.v4);
585 if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
586 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
587 Status = EFI_INVALID_PARAMETER;
588 } else {
589 CopyMem (&Private->Current->SessionConfigData.TargetIp, &HostIp.v4, sizeof (HostIp.v4));
590 }
591
592 break;
593
594 case KEY_TARGET_NAME:
595 IScsiUnicodeStrToAsciiStr (IfrNvData->TargetName, IScsiName);
596 Status = IScsiNormalizeName (IScsiName, AsciiStrLen (IScsiName));
597 if (EFI_ERROR (Status)) {
598 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid iSCSI Name!", NULL);
599 } else {
600 AsciiStrCpy (Private->Current->SessionConfigData.TargetName, IScsiName);
601 }
602
603 break;
604
605 case KEY_DHCP_ENABLE:
606 if (IfrNvData->InitiatorInfoFromDhcp == 0) {
607 IfrNvData->TargetInfoFromDhcp = 0;
608 }
609
610 break;
611
612 case KEY_BOOT_LUN:
613 IScsiUnicodeStrToAsciiStr (IfrNvData->BootLun, LunString);
614 Status = IScsiAsciiStrToLun (LunString, (UINT8 *) &Lun);
615 if (EFI_ERROR (Status)) {
616 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid LUN string!", NULL);
617 } else {
618 CopyMem (Private->Current->SessionConfigData.BootLun, &Lun, sizeof (Lun));
619 }
620
621 break;
622
623 case KEY_CHAP_NAME:
624 IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPName, Private->Current->AuthConfigData.CHAPName);
625 break;
626
627 case KEY_CHAP_SECRET:
628 IScsiUnicodeStrToAsciiStr (IfrNvData->CHAPSecret, Private->Current->AuthConfigData.CHAPSecret);
629 break;
630
631 case KEY_REVERSE_CHAP_NAME:
632 IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPName, Private->Current->AuthConfigData.ReverseCHAPName);
633 break;
634
635 case KEY_REVERSE_CHAP_SECRET:
636 IScsiUnicodeStrToAsciiStr (IfrNvData->ReverseCHAPSecret, Private->Current->AuthConfigData.ReverseCHAPSecret);
637 break;
638
639 case KEY_SAVE_CHANGES:
640 //
641 // First, update those fields which don't have INTERACTIVE set.
642 //
643 Private->Current->SessionConfigData.Enabled = IfrNvData->Enabled;
644 Private->Current->SessionConfigData.InitiatorInfoFromDhcp = IfrNvData->InitiatorInfoFromDhcp;
645 Private->Current->SessionConfigData.TargetPort = IfrNvData->TargetPort;
646 if (Private->Current->SessionConfigData.TargetPort == 0) {
647 Private->Current->SessionConfigData.TargetPort = ISCSI_WELL_KNOWN_PORT;
648 }
649
650 Private->Current->SessionConfigData.TargetInfoFromDhcp = IfrNvData->TargetInfoFromDhcp;
651 Private->Current->AuthConfigData.CHAPType = IfrNvData->CHAPType;
652
653 //
654 // Only do full parameter validation if iSCSI is enabled on this device.
655 //
656 if (Private->Current->SessionConfigData.Enabled) {
657 //
658 // Validate the address configuration of the Initiator if DHCP isn't
659 // deployed.
660 //
661 if (!Private->Current->SessionConfigData.InitiatorInfoFromDhcp) {
662 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.LocalIp, sizeof (HostIp.v4));
663 CopyMem (&SubnetMask.v4, &Private->Current->SessionConfigData.SubnetMask, sizeof (SubnetMask.v4));
664 CopyMem (&Gateway.v4, &Private->Current->SessionConfigData.Gateway, sizeof (Gateway.v4));
665
666 if ((Gateway.Addr[0] != 0)) {
667 if (SubnetMask.Addr[0] == 0) {
668 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Gateway address is set but subnet mask is zero.", NULL);
669 Status = EFI_INVALID_PARAMETER;
670 break;
671 } else if (!IP4_NET_EQUAL (HostIp.Addr[0], Gateway.Addr[0], SubnetMask.Addr[0])) {
672 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Local IP and Gateway are not in the same subnet.", NULL);
673 Status = EFI_INVALID_PARAMETER;
674 break;
675 }
676 }
677 }
678 //
679 // Validate target configuration if DHCP isn't deployed.
680 //
681 if (!Private->Current->SessionConfigData.TargetInfoFromDhcp) {
682 CopyMem (&HostIp.v4, &Private->Current->SessionConfigData.TargetIp, sizeof (HostIp.v4));
683 if (!NetIp4IsUnicast (NTOHL (HostIp.Addr[0]), 0)) {
684 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Target IP is invalid!", NULL);
685 Status = EFI_INVALID_PARAMETER;
686 break;
687 }
688 }
689
690 if (IfrNvData->CHAPType != ISCSI_CHAP_NONE) {
691 if ((IfrNvData->CHAPName[0] == '\0') || (IfrNvData->CHAPSecret[0] == '\0')) {
692 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"CHAP Name or CHAP Secret is invalid!", NULL);
693 Status = EFI_INVALID_PARAMETER;
694 break;
695 }
696
697 if ((IfrNvData->CHAPType == ISCSI_CHAP_MUTUAL) &&
698 ((IfrNvData->ReverseCHAPName[0] == '\0') || (IfrNvData->ReverseCHAPSecret[0] == '\0'))
699 ) {
700 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Reverse CHAP Name or Reverse CHAP Secret is invalid!", NULL);
701 Status = EFI_INVALID_PARAMETER;
702 break;
703 }
704 }
705 }
706
707 BufferSize = sizeof (Private->Current->SessionConfigData);
708 gRT->SetVariable (
709 Private->Current->MacString,
710 &gEfiIScsiInitiatorNameProtocolGuid,
711 ISCSI_CONFIG_VAR_ATTR,
712 BufferSize,
713 &Private->Current->SessionConfigData
714 );
715
716 BufferSize = sizeof (Private->Current->AuthConfigData);
717 gRT->SetVariable (
718 Private->Current->MacString,
719 &mIScsiCHAPAuthInfoGuid,
720 ISCSI_CONFIG_VAR_ATTR,
721 BufferSize,
722 &Private->Current->AuthConfigData
723 );
724 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
725 break;
726
727 default:
728 if ((QuestionId >= KEY_DEVICE_ENTRY_BASE) && (QuestionId < (mNumberOfIScsiDevices + KEY_DEVICE_ENTRY_BASE))) {
729 //
730 // In case goto the device configuration form, update the device form title.
731 //
732 ConfigFormEntry = IScsiGetConfigFormEntryByIndex ((UINT32) (QuestionId - KEY_DEVICE_ENTRY_BASE));
733 ASSERT (ConfigFormEntry != NULL);
734
735 UnicodeSPrint (PortString, (UINTN) 128, L"Port %s", ConfigFormEntry->MacString);
736 DeviceFormTitleToken = (EFI_STRING_ID) STR_ISCSI_DEVICE_FORM_TITLE;
737 HiiSetString (Private->RegisteredHandle, DeviceFormTitleToken, PortString, NULL);
738
739 IScsiConvertDeviceConfigDataToIfrNvData (ConfigFormEntry, IfrNvData);
740
741 Private->Current = ConfigFormEntry;
742 }
743
744 break;
745 }
746
747 if (!EFI_ERROR (Status)) {
748 //
749 // Pass changed uncommitted data back to Form Browser
750 //
751 HiiSetBrowserData (&mVendorGuid, mVendorStorageName, sizeof (ISCSI_CONFIG_IFR_NVDATA), (UINT8 *) IfrNvData, NULL);
752 }
753
754 FreePool (IfrNvData);
755 return Status;
756 }
757
758 /**
759 Updates the iSCSI configuration form to add/delete an entry for the iSCSI
760 device specified by the Controller.
761
762 @param[in] DriverBindingHandle The driverbinding handle.
763 @param[in] Controller The controller handle of the iSCSI device.
764 @param[in] AddForm Whether to add or delete a form entry.
765
766 @retval EFI_SUCCESS The iSCSI configuration form is updated.
767 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
768 @retval Others Other errors as indicated.
769 **/
770 EFI_STATUS
771 IScsiConfigUpdateForm (
772 IN EFI_HANDLE DriverBindingHandle,
773 IN EFI_HANDLE Controller,
774 IN BOOLEAN AddForm
775 )
776 {
777 LIST_ENTRY *Entry;
778 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
779 BOOLEAN EntryExisted;
780 EFI_STATUS Status;
781 EFI_MAC_ADDRESS MacAddress;
782 UINTN HwAddressSize;
783 UINT16 VlanId;
784 CHAR16 PortString[128];
785 UINT16 FormIndex;
786 UINTN BufferSize;
787 VOID *StartOpCodeHandle;
788 VOID *EndOpCodeHandle;
789 EFI_IFR_GUID_LABEL *StartLabel;
790 EFI_IFR_GUID_LABEL *EndLabel;
791
792 ConfigFormEntry = NULL;
793 EntryExisted = FALSE;
794
795 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
796 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
797
798 if (ConfigFormEntry->Controller == Controller) {
799 EntryExisted = TRUE;
800 break;
801 }
802 }
803
804 if (AddForm) {
805 if (EntryExisted) {
806 return EFI_SUCCESS;
807 } else {
808 //
809 // Add a new form.
810 //
811 ConfigFormEntry = (ISCSI_CONFIG_FORM_ENTRY *) AllocateZeroPool (sizeof (ISCSI_CONFIG_FORM_ENTRY));
812 if (ConfigFormEntry == NULL) {
813 return EFI_OUT_OF_RESOURCES;
814 }
815
816 InitializeListHead (&ConfigFormEntry->Link);
817 ConfigFormEntry->Controller = Controller;
818
819 //
820 // Get the MAC address and convert it into the formatted string.
821 //
822 Status = NetLibGetMacAddress (Controller, &MacAddress, &HwAddressSize);
823 ASSERT (Status == EFI_SUCCESS);
824 VlanId = NetLibGetVlanId (Controller);
825
826 IScsiMacAddrToStr (&MacAddress, (UINT32) HwAddressSize, VlanId, ConfigFormEntry->MacString);
827
828 //
829 // Get the normal session configuration data.
830 //
831 BufferSize = sizeof (ConfigFormEntry->SessionConfigData);
832 Status = gRT->GetVariable (
833 ConfigFormEntry->MacString,
834 &gEfiIScsiInitiatorNameProtocolGuid,
835 NULL,
836 &BufferSize,
837 &ConfigFormEntry->SessionConfigData
838 );
839 if (EFI_ERROR (Status)) {
840 ZeroMem (&ConfigFormEntry->SessionConfigData, sizeof (ConfigFormEntry->SessionConfigData));
841 }
842 //
843 // Get the CHAP authentication configuration data.
844 //
845 BufferSize = sizeof (ConfigFormEntry->AuthConfigData);
846 Status = gRT->GetVariable (
847 ConfigFormEntry->MacString,
848 &mIScsiCHAPAuthInfoGuid,
849 NULL,
850 &BufferSize,
851 &ConfigFormEntry->AuthConfigData
852 );
853 if (EFI_ERROR (Status)) {
854 ZeroMem (&ConfigFormEntry->AuthConfigData, sizeof (ConfigFormEntry->AuthConfigData));
855 }
856 //
857 // Compose the Port string and create a new EFI_STRING_ID.
858 //
859 UnicodeSPrint (PortString, 128, L"Port %s", ConfigFormEntry->MacString);
860 ConfigFormEntry->PortTitleToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
861
862 //
863 // Compose the help string of this port and create a new EFI_STRING_ID.
864 //
865 UnicodeSPrint (PortString, 128, L"Set the iSCSI parameters on port %s", ConfigFormEntry->MacString);
866 ConfigFormEntry->PortTitleHelpToken = HiiSetString (mCallbackInfo->RegisteredHandle, 0, PortString, NULL);
867
868 InsertTailList (&mIScsiConfigFormList, &ConfigFormEntry->Link);
869 mNumberOfIScsiDevices++;
870 }
871 } else {
872 ASSERT (EntryExisted);
873
874 mNumberOfIScsiDevices--;
875 RemoveEntryList (&ConfigFormEntry->Link);
876 FreePool (ConfigFormEntry);
877 }
878 //
879 // Allocate space for creation of Buffer
880 //
881
882 //
883 // Init OpCode Handle
884 //
885 StartOpCodeHandle = HiiAllocateOpCodeHandle ();
886 ASSERT (StartOpCodeHandle != NULL);
887
888 EndOpCodeHandle = HiiAllocateOpCodeHandle ();
889 ASSERT (EndOpCodeHandle != NULL);
890
891 //
892 // Create Hii Extend Label OpCode as the start opcode
893 //
894 StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
895 StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
896 StartLabel->Number = DEVICE_ENTRY_LABEL;
897
898 //
899 // Create Hii Extend Label OpCode as the end opcode
900 //
901 EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
902 EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
903 EndLabel->Number = LABEL_END;
904
905 FormIndex = 0;
906 NET_LIST_FOR_EACH (Entry, &mIScsiConfigFormList) {
907 ConfigFormEntry = NET_LIST_USER_STRUCT (Entry, ISCSI_CONFIG_FORM_ENTRY, Link);
908
909 HiiCreateGotoOpCode (
910 StartOpCodeHandle, // Container for dynamic created opcodes
911 FORMID_DEVICE_FORM, // Target Form ID
912 ConfigFormEntry->PortTitleToken, // Prompt text
913 ConfigFormEntry->PortTitleHelpToken, // Help text
914 EFI_IFR_FLAG_CALLBACK, // Question flag
915 (UINT16)(KEY_DEVICE_ENTRY_BASE + FormIndex) // Question ID
916 );
917
918 FormIndex++;
919 }
920
921 HiiUpdateForm (
922 mCallbackInfo->RegisteredHandle,
923 &mVendorGuid,
924 FORMID_MAIN_FORM,
925 StartOpCodeHandle, // Label DEVICE_ENTRY_LABEL
926 EndOpCodeHandle // LABEL_END
927 );
928
929 HiiFreeOpCodeHandle (StartOpCodeHandle);
930 HiiFreeOpCodeHandle (EndOpCodeHandle);
931
932 return EFI_SUCCESS;
933 }
934
935 /**
936 Initialize the iSCSI configuration form.
937
938 @param[in] DriverBindingHandle The iSCSI driverbinding handle.
939
940 @retval EFI_SUCCESS The iSCSI configuration form is initialized.
941 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
942 @retval Others Other errors as indicated.
943 **/
944 EFI_STATUS
945 IScsiConfigFormInit (
946 VOID
947 )
948 {
949 EFI_STATUS Status;
950 EFI_HII_DATABASE_PROTOCOL *HiiDatabase;
951 ISCSI_FORM_CALLBACK_INFO *CallbackInfo;
952
953 Status = gBS->LocateProtocol (&gEfiHiiDatabaseProtocolGuid, NULL, (VOID **)&HiiDatabase);
954 if (EFI_ERROR (Status)) {
955 return Status;
956 }
957
958 CallbackInfo = (ISCSI_FORM_CALLBACK_INFO *) AllocateZeroPool (sizeof (ISCSI_FORM_CALLBACK_INFO));
959 if (CallbackInfo == NULL) {
960 return EFI_OUT_OF_RESOURCES;
961 }
962
963 CallbackInfo->Signature = ISCSI_FORM_CALLBACK_INFO_SIGNATURE;
964 CallbackInfo->HiiDatabase = HiiDatabase;
965 CallbackInfo->Current = NULL;
966
967 CallbackInfo->ConfigAccess.ExtractConfig = IScsiFormExtractConfig;
968 CallbackInfo->ConfigAccess.RouteConfig = IScsiFormRouteConfig;
969 CallbackInfo->ConfigAccess.Callback = IScsiFormCallback;
970
971 Status = gBS->LocateProtocol (&gEfiHiiConfigRoutingProtocolGuid, NULL, (VOID **)&CallbackInfo->ConfigRouting);
972 if (EFI_ERROR (Status)) {
973 FreePool(CallbackInfo);
974 return Status;
975 }
976
977 //
978 // Install Device Path Protocol and Config Access protocol to driver handle
979 //
980 Status = gBS->InstallMultipleProtocolInterfaces (
981 &CallbackInfo->DriverHandle,
982 &gEfiDevicePathProtocolGuid,
983 &mIScsiHiiVendorDevicePath,
984 &gEfiHiiConfigAccessProtocolGuid,
985 &CallbackInfo->ConfigAccess,
986 NULL
987 );
988 ASSERT_EFI_ERROR (Status);
989
990 //
991 // Publish our HII data
992 //
993 CallbackInfo->RegisteredHandle = HiiAddPackages (
994 &mVendorGuid,
995 CallbackInfo->DriverHandle,
996 IScsiDxeStrings,
997 IScsiConfigDxeBin,
998 NULL
999 );
1000 if (CallbackInfo->RegisteredHandle == NULL) {
1001 FreePool(CallbackInfo);
1002 return EFI_OUT_OF_RESOURCES;
1003 }
1004
1005 mCallbackInfo = CallbackInfo;
1006
1007 return Status;
1008 }
1009
1010 /**
1011 Unload the iSCSI configuration form, this includes: delete all the iSCSI
1012 device configuration entries, uninstall the form callback protocol and
1013 free the resources used.
1014
1015 @param[in] DriverBindingHandle The iSCSI driverbinding handle.
1016
1017 @retval EFI_SUCCESS The iSCSI configuration form is unloaded.
1018 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
1019 **/
1020 EFI_STATUS
1021 IScsiConfigFormUnload (
1022 IN EFI_HANDLE DriverBindingHandle
1023 )
1024 {
1025 ISCSI_CONFIG_FORM_ENTRY *ConfigFormEntry;
1026
1027 while (!IsListEmpty (&mIScsiConfigFormList)) {
1028 //
1029 // Uninstall the device forms as the iSCSI driver instance may fail to
1030 // control the controller but still install the device configuration form.
1031 // In such case, upon driver unloading, the driver instance's driverbinding.
1032 // stop () won't be called, so we have to take this chance here to uninstall
1033 // the device form.
1034 //
1035 ConfigFormEntry = NET_LIST_USER_STRUCT (mIScsiConfigFormList.ForwardLink, ISCSI_CONFIG_FORM_ENTRY, Link);
1036 IScsiConfigUpdateForm (DriverBindingHandle, ConfigFormEntry->Controller, FALSE);
1037 }
1038
1039 //
1040 // Remove HII package list
1041 //
1042 mCallbackInfo->HiiDatabase->RemovePackageList (
1043 mCallbackInfo->HiiDatabase,
1044 mCallbackInfo->RegisteredHandle
1045 );
1046
1047 //
1048 // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
1049 //
1050 gBS->UninstallMultipleProtocolInterfaces (
1051 mCallbackInfo->DriverHandle,
1052 &gEfiDevicePathProtocolGuid,
1053 &mIScsiHiiVendorDevicePath,
1054 &gEfiHiiConfigAccessProtocolGuid,
1055 &mCallbackInfo->ConfigAccess,
1056 NULL
1057 );
1058 FreePool (mCallbackInfo);
1059
1060 return EFI_SUCCESS;
1061 }