]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/IScsiDxe/IScsiMisc.c
Clean up the private GUID definition in module Level.
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiMisc.c
1 /** @file
2 Miscellaneous routines for iSCSI driver.
3
4 Copyright (c) 2004 - 2011, 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 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 IScsiHexString[] = "0123456789ABCDEFabcdef";
18
19 /**
20 Removes (trims) specified leading and trailing characters from a string.
21
22 @param[in, out] Str Pointer to the null-terminated string to be trimmed.
23 On return, Str will hold the trimmed string.
24
25 @param[in] CharC Character will be trimmed from str.
26
27 **/
28 VOID
29 IScsiStrTrim (
30 IN OUT CHAR16 *Str,
31 IN CHAR16 CharC
32 )
33 {
34 CHAR16 *Pointer1;
35 CHAR16 *Pointer2;
36
37 if (*Str == 0) {
38 return ;
39 }
40
41 //
42 // Trim off the leading and trailing characters c
43 //
44 for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
45 ;
46 }
47
48 Pointer2 = Str;
49 if (Pointer2 == Pointer1) {
50 while (*Pointer1 != 0) {
51 Pointer2++;
52 Pointer1++;
53 }
54 } else {
55 while (*Pointer1 != 0) {
56 *Pointer2 = *Pointer1;
57 Pointer1++;
58 Pointer2++;
59 }
60 *Pointer2 = 0;
61 }
62
63
64 for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
65 ;
66 }
67 if (Pointer1 != Str + StrLen(Str) - 1) {
68 *(Pointer1 + 1) = 0;
69 }
70 }
71
72 /**
73 Calculate the prefix length of the IPv4 subnet mask.
74
75 @param[in] SubnetMask The IPv4 subnet mask.
76
77 @return The prefix length of the subnet mask.
78 @retval 0 Other errors as indicated.
79
80 **/
81 UINT8
82 IScsiGetSubnetMaskPrefixLength (
83 IN EFI_IPv4_ADDRESS *SubnetMask
84 )
85 {
86 UINT8 Len;
87 UINT32 ReverseMask;
88
89 //
90 // The SubnetMask is in network byte order.
91 //
92 ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
93
94 //
95 // Reverse it.
96 //
97 ReverseMask = ~ReverseMask;
98
99 if ((ReverseMask & (ReverseMask + 1)) != 0) {
100 return 0;
101 }
102
103 Len = 0;
104
105 while (ReverseMask != 0) {
106 ReverseMask = ReverseMask >> 1;
107 Len++;
108 }
109
110 return (UINT8) (32 - Len);
111 }
112
113
114 /**
115 Convert the hexadecimal encoded LUN string into the 64-bit LUN.
116
117 @param[in] Str The hexadecimal encoded LUN string.
118 @param[out] Lun Storage to return the 64-bit LUN.
119
120 @retval EFI_SUCCESS The 64-bit LUN is stored in Lun.
121 @retval EFI_INVALID_PARAMETER The string is malformatted.
122
123 **/
124 EFI_STATUS
125 IScsiAsciiStrToLun (
126 IN CHAR8 *Str,
127 OUT UINT8 *Lun
128 )
129 {
130 UINTN Index, IndexValue, IndexNum, SizeStr;
131 CHAR8 TemStr[2];
132 UINT8 TemValue;
133 UINT16 Value[4];
134
135 ZeroMem (Lun, 8);
136 ZeroMem (TemStr, 2);
137 ZeroMem ((UINT8 *) Value, sizeof (Value));
138 SizeStr = AsciiStrLen (Str);
139 IndexValue = 0;
140 IndexNum = 0;
141
142 for (Index = 0; Index < SizeStr; Index ++) {
143 TemStr[0] = Str[Index];
144 TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);
145 if (TemValue == 0 && TemStr[0] != '0') {
146 if ((TemStr[0] != '-') || (IndexNum == 0)) {
147 //
148 // Invalid Lun Char.
149 //
150 return EFI_INVALID_PARAMETER;
151 }
152 }
153
154 if ((TemValue == 0) && (TemStr[0] == '-')) {
155 //
156 // Next Lun value.
157 //
158 if (++IndexValue >= 4) {
159 //
160 // Max 4 Lun value.
161 //
162 return EFI_INVALID_PARAMETER;
163 }
164 //
165 // Restart str index for the next lun value.
166 //
167 IndexNum = 0;
168 continue;
169 }
170
171 if (++IndexNum > 4) {
172 //
173 // Each Lun Str can't exceed size 4, because it will be as UINT16 value.
174 //
175 return EFI_INVALID_PARAMETER;
176 }
177
178 //
179 // Combine UINT16 value.
180 //
181 Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);
182 }
183
184 for (Index = 0; Index <= IndexValue; Index ++) {
185 *((UINT16 *) &Lun[Index * 2]) = HTONS (Value[Index]);
186 }
187
188 return EFI_SUCCESS;
189 }
190
191 /**
192 Convert the 64-bit LUN into the hexadecimal encoded LUN string.
193
194 @param[in] Lun The 64-bit LUN.
195 @param[out] Str The storage to return the hexadecimal encoded LUN string.
196
197 **/
198 VOID
199 IScsiLunToUnicodeStr (
200 IN UINT8 *Lun,
201 OUT CHAR16 *Str
202 )
203 {
204 UINTN Index;
205 CHAR16 *TempStr;
206
207 TempStr = Str;
208
209 for (Index = 0; Index < 4; Index++) {
210
211 if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {
212 StrCpy (TempStr, L"0-");
213 } else {
214 TempStr[0] = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];
215 TempStr[1] = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];
216 TempStr[2] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];
217 TempStr[3] = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];
218 TempStr[4] = L'-';
219 TempStr[5] = 0;
220
221 IScsiStrTrim (TempStr, L'0');
222 }
223
224 TempStr += StrLen (TempStr);
225 }
226
227 Str[StrLen (Str) - 1] = 0;
228
229 for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
230 if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
231 Str[Index - 1] = 0;
232 } else {
233 break;
234 }
235 }
236 }
237
238 /**
239 Convert the formatted IP address into the binary IP address.
240
241 @param[in] Str The UNICODE string.
242 @param[in] IpMode Indicates whether the IP address is v4 or v6.
243 @param[out] Ip The storage to return the ASCII string.
244
245 @retval EFI_SUCCESS The binary IP address is returned in Ip.
246 @retval EFI_INVALID_PARAMETER The IP string is malformatted or IpMode is
247 invalid.
248
249 **/
250 EFI_STATUS
251 IScsiAsciiStrToIp (
252 IN CHAR8 *Str,
253 IN UINT8 IpMode,
254 OUT EFI_IP_ADDRESS *Ip
255 )
256 {
257 EFI_STATUS Status;
258
259 if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {
260 return NetLibAsciiStrToIp4 (Str, &Ip->v4);
261
262 } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {
263 return NetLibAsciiStrToIp6 (Str, &Ip->v6);
264
265 } else if (IpMode == IP_MODE_AUTOCONFIG) {
266 Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);
267 if (!EFI_ERROR (Status)) {
268 return Status;
269 }
270 return NetLibAsciiStrToIp6 (Str, &Ip->v6);
271
272 }
273
274 return EFI_INVALID_PARAMETER;
275 }
276
277 /**
278 Convert the mac address into a hexadecimal encoded "-" seperated string.
279
280 @param[in] Mac The mac address.
281 @param[in] Len Length in bytes of the mac address.
282 @param[in] VlanId VLAN ID of the network device.
283 @param[out] Str The storage to return the mac string.
284
285 **/
286 VOID
287 IScsiMacAddrToStr (
288 IN EFI_MAC_ADDRESS *Mac,
289 IN UINT32 Len,
290 IN UINT16 VlanId,
291 OUT CHAR16 *Str
292 )
293 {
294 UINT32 Index;
295 CHAR16 *String;
296
297 for (Index = 0; Index < Len; Index++) {
298 Str[3 * Index] = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];
299 Str[3 * Index + 1] = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];
300 Str[3 * Index + 2] = L':';
301 }
302
303 String = &Str[3 * Index - 1] ;
304 if (VlanId != 0) {
305 String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
306 }
307
308 *String = L'\0';
309 }
310
311 /**
312 Convert the binary encoded buffer into a hexadecimal encoded string.
313
314 @param[in] BinBuffer The buffer containing the binary data.
315 @param[in] BinLength Length of the binary buffer.
316 @param[in, out] HexStr Pointer to the string.
317 @param[in, out] HexLength The length of the string.
318
319 @retval EFI_SUCCESS The binary data is converted to the hexadecimal string
320 and the length of the string is updated.
321 @retval EFI_BUFFER_TOO_SMALL The string is too small.
322 @retval EFI_INVALID_PARAMETER The IP string is malformatted.
323
324 **/
325 EFI_STATUS
326 IScsiBinToHex (
327 IN UINT8 *BinBuffer,
328 IN UINT32 BinLength,
329 IN OUT CHAR8 *HexStr,
330 IN OUT UINT32 *HexLength
331 )
332 {
333 UINTN Index;
334
335 if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
336 return EFI_INVALID_PARAMETER;
337 }
338
339 if (((*HexLength) - 3) < BinLength * 2) {
340 *HexLength = BinLength * 2 + 3;
341 return EFI_BUFFER_TOO_SMALL;
342 }
343
344 *HexLength = BinLength * 2 + 3;
345 //
346 // Prefix for Hex String.
347 //
348 HexStr[0] = '0';
349 HexStr[1] = 'x';
350
351 for (Index = 0; Index < BinLength; Index++) {
352 HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];
353 HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];
354 }
355
356 HexStr[Index * 2 + 2] = '\0';
357
358 return EFI_SUCCESS;
359 }
360
361
362 /**
363 Convert the hexadecimal string into a binary encoded buffer.
364
365 @param[in, out] BinBuffer The binary buffer.
366 @param[in, out] BinLength Length of the binary buffer.
367 @param[in] HexStr The hexadecimal string.
368
369 @retval EFI_SUCCESS The hexadecimal string is converted into a binary
370 encoded buffer.
371 @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
372
373 **/
374 EFI_STATUS
375 IScsiHexToBin (
376 IN OUT UINT8 *BinBuffer,
377 IN OUT UINT32 *BinLength,
378 IN CHAR8 *HexStr
379 )
380 {
381 UINTN Index;
382 UINTN Length;
383 UINT8 Digit;
384 CHAR8 TemStr[2];
385
386 ZeroMem (TemStr, sizeof (TemStr));
387
388 //
389 // Find out how many hex characters the string has.
390 //
391 if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
392 HexStr += 2;
393 }
394
395 Length = AsciiStrLen (HexStr);
396
397 for (Index = 0; Index < Length; Index ++) {
398 TemStr[0] = HexStr[Index];
399 Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
400 if (Digit == 0 && TemStr[0] != '0') {
401 //
402 // Invalid Lun Char.
403 //
404 break;
405 }
406 if ((Index & 1) == 0) {
407 BinBuffer [Index/2] = Digit;
408 } else {
409 BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
410 }
411 }
412
413 *BinLength = (UINT32) ((Index + 1)/2);
414
415 return EFI_SUCCESS;
416 }
417
418
419 /**
420 Convert the decimal-constant string or hex-constant string into a numerical value.
421
422 @param[in] Str String in decimal or hex.
423
424 @return The numerical value.
425
426 **/
427 UINTN
428 IScsiNetNtoi (
429 IN CHAR8 *Str
430 )
431 {
432 if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {
433 Str += 2;
434
435 return AsciiStrHexToUintn (Str);
436 }
437
438 return AsciiStrDecimalToUintn (Str);
439 }
440
441
442 /**
443 Generate random numbers.
444
445 @param[in, out] Rand The buffer to contain random numbers.
446 @param[in] RandLength The length of the Rand buffer.
447
448 **/
449 VOID
450 IScsiGenRandom (
451 IN OUT UINT8 *Rand,
452 IN UINTN RandLength
453 )
454 {
455 UINT32 Random;
456
457 while (RandLength > 0) {
458 Random = NET_RANDOM (NetRandomInitSeed ());
459 *Rand++ = (UINT8) (Random);
460 RandLength--;
461 }
462 }
463
464
465 /**
466 Record the NIC info in global structure.
467
468 @param[in] Controller The handle of the controller.
469
470 @retval EFI_SUCCESS The operation is completed.
471 @retval EFI_OUT_OF_RESOURCES Do not have sufficient resources to finish this
472 operation.
473
474 **/
475 EFI_STATUS
476 IScsiAddNic (
477 IN EFI_HANDLE Controller
478 )
479 {
480 EFI_STATUS Status;
481 ISCSI_NIC_INFO *NicInfo;
482 LIST_ENTRY *Entry;
483 EFI_MAC_ADDRESS MacAddr;
484 UINTN HwAddressSize;
485 UINT16 VlanId;
486
487 //
488 // Get MAC address of this network device.
489 //
490 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
491 if (EFI_ERROR (Status)) {
492 return Status;
493 }
494
495 //
496 // Get VLAN ID of this network device.
497 //
498 VlanId = NetLibGetVlanId (Controller);
499
500 //
501 // Check whether the NIC info already exists. Return directly if so.
502 //
503 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
504 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
505 if (NicInfo->HwAddressSize == HwAddressSize &&
506 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
507 NicInfo->VlanId == VlanId) {
508 mPrivate->CurrentNic = NicInfo->NicIndex;
509 return EFI_SUCCESS;
510 }
511
512 if (mPrivate->MaxNic < NicInfo->NicIndex) {
513 mPrivate->MaxNic = NicInfo->NicIndex;
514 }
515 }
516
517 //
518 // Record the NIC info in private structure.
519 //
520 NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));
521 if (NicInfo == NULL) {
522 return EFI_OUT_OF_RESOURCES;
523 }
524
525 CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);
526 NicInfo->HwAddressSize = (UINT32) HwAddressSize;
527 NicInfo->VlanId = VlanId;
528 NicInfo->NicIndex = (UINT8) (mPrivate->MaxNic + 1);
529 mPrivate->MaxNic = NicInfo->NicIndex;
530
531 //
532 // Get the PCI location.
533 //
534 IScsiGetNICPciLocation (
535 Controller,
536 &NicInfo->BusNumber,
537 &NicInfo->DeviceNumber,
538 &NicInfo->FunctionNumber
539 );
540
541 InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);
542 mPrivate->NicCount++;
543
544 mPrivate->CurrentNic = NicInfo->NicIndex;
545 return EFI_SUCCESS;
546 }
547
548
549 /**
550 Delete the recorded NIC info from global structure. Also delete corresponding
551 attempts.
552
553 @param[in] Controller The handle of the controller.
554
555 @retval EFI_SUCCESS The operation is completed.
556 @retval EFI_NOT_FOUND The NIC info to be deleted is not recorded.
557
558 **/
559 EFI_STATUS
560 IScsiRemoveNic (
561 IN EFI_HANDLE Controller
562 )
563 {
564 EFI_STATUS Status;
565 ISCSI_NIC_INFO *NicInfo;
566 LIST_ENTRY *Entry;
567 LIST_ENTRY *NextEntry;
568 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
569 ISCSI_NIC_INFO *ThisNic;
570 EFI_MAC_ADDRESS MacAddr;
571 UINTN HwAddressSize;
572 UINT16 VlanId;
573
574 //
575 // Get MAC address of this network device.
576 //
577 Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
578 if (EFI_ERROR (Status)) {
579 return Status;
580 }
581
582 //
583 // Get VLAN ID of this network device.
584 //
585 VlanId = NetLibGetVlanId (Controller);
586
587 //
588 // Check whether the NIC information exists.
589 //
590 ThisNic = NULL;
591
592 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
593 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
594 if (NicInfo->HwAddressSize == HwAddressSize &&
595 CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
596 NicInfo->VlanId == VlanId) {
597
598 ThisNic = NicInfo;
599 break;
600 }
601 }
602
603 if (ThisNic == NULL) {
604 return EFI_NOT_FOUND;
605 }
606
607 mPrivate->CurrentNic = ThisNic->NicIndex;
608
609 RemoveEntryList (&ThisNic->Link);
610 FreePool (ThisNic);
611 mPrivate->NicCount--;
612
613 //
614 // Remove all attempts related to this NIC.
615 //
616 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
617 AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
618 if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {
619 RemoveEntryList (&AttemptConfigData->Link);
620 mPrivate->AttemptCount--;
621
622 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {
623 if (--mPrivate->MpioCount == 0) {
624 mPrivate->EnableMpio = FALSE;
625 }
626
627 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {
628 mPrivate->Krb5MpioCount--;
629 }
630
631 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {
632 mPrivate->SinglePathCount--;
633
634 if (mPrivate->ValidSinglePathCount > 0) {
635 mPrivate->ValidSinglePathCount--;
636 }
637 }
638
639 FreePool (AttemptConfigData);
640 }
641 }
642
643 //
644 // Free attempt is created but not saved to system.
645 //
646 if (mPrivate->NewAttempt != NULL) {
647 FreePool (mPrivate->NewAttempt);
648 mPrivate->NewAttempt = NULL;
649 }
650
651 return EFI_SUCCESS;
652 }
653
654
655 /**
656 Get the recorded NIC info from global structure by the Index.
657
658 @param[in] NicIndex The index indicates the position of NIC info.
659
660 @return Pointer to the NIC info, or NULL if not found.
661
662 **/
663 ISCSI_NIC_INFO *
664 IScsiGetNicInfoByIndex (
665 IN UINT8 NicIndex
666 )
667 {
668 LIST_ENTRY *Entry;
669 ISCSI_NIC_INFO *NicInfo;
670
671 NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
672 NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
673 if (NicInfo->NicIndex == NicIndex) {
674 return NicInfo;
675 }
676 }
677
678 return NULL;
679 }
680
681
682 /**
683 Get the NIC's PCI location and return it accroding to the composited
684 format defined in iSCSI Boot Firmware Table.
685
686 @param[in] Controller The handle of the controller.
687 @param[out] Bus The bus number.
688 @param[out] Device The device number.
689 @param[out] Function The function number.
690
691 @return The composited representation of the NIC PCI location.
692
693 **/
694 UINT16
695 IScsiGetNICPciLocation (
696 IN EFI_HANDLE Controller,
697 OUT UINTN *Bus,
698 OUT UINTN *Device,
699 OUT UINTN *Function
700 )
701 {
702 EFI_STATUS Status;
703 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
704 EFI_HANDLE PciIoHandle;
705 EFI_PCI_IO_PROTOCOL *PciIo;
706 UINTN Segment;
707
708 Status = gBS->HandleProtocol (
709 Controller,
710 &gEfiDevicePathProtocolGuid,
711 (VOID **) &DevicePath
712 );
713 if (EFI_ERROR (Status)) {
714 return 0;
715 }
716
717 Status = gBS->LocateDevicePath (
718 &gEfiPciIoProtocolGuid,
719 &DevicePath,
720 &PciIoHandle
721 );
722 if (EFI_ERROR (Status)) {
723 return 0;
724 }
725
726 Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
727 if (EFI_ERROR (Status)) {
728 return 0;
729 }
730
731 Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);
732 if (EFI_ERROR (Status)) {
733 return 0;
734 }
735
736 return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);
737 }
738
739
740 /**
741 Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
742 buffer, and the size of the buffer. If failure, return NULL.
743
744 @param[in] Name String part of EFI variable name.
745 @param[in] VendorGuid GUID part of EFI variable name.
746 @param[out] VariableSize Returns the size of the EFI variable that was read.
747
748 @return Dynamically allocated memory that contains a copy of the EFI variable.
749 @return Caller is responsible freeing the buffer.
750 @retval NULL Variable was not read.
751
752 **/
753 VOID *
754 IScsiGetVariableAndSize (
755 IN CHAR16 *Name,
756 IN EFI_GUID *VendorGuid,
757 OUT UINTN *VariableSize
758 )
759 {
760 EFI_STATUS Status;
761 UINTN BufferSize;
762 VOID *Buffer;
763
764 Buffer = NULL;
765
766 //
767 // Pass in a zero size buffer to find the required buffer size.
768 //
769 BufferSize = 0;
770 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
771 if (Status == EFI_BUFFER_TOO_SMALL) {
772 //
773 // Allocate the buffer to return
774 //
775 Buffer = AllocateZeroPool (BufferSize);
776 if (Buffer == NULL) {
777 return NULL;
778 }
779 //
780 // Read variable into the allocated buffer.
781 //
782 Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
783 if (EFI_ERROR (Status)) {
784 BufferSize = 0;
785 }
786 }
787
788 *VariableSize = BufferSize;
789 return Buffer;
790 }
791
792
793 /**
794 Create the iSCSI driver data.
795
796 @param[in] Image The handle of the driver image.
797 @param[in] Controller The handle of the controller.
798
799 @return The iSCSI driver data created.
800 @retval NULL Other errors as indicated.
801
802 **/
803 ISCSI_DRIVER_DATA *
804 IScsiCreateDriverData (
805 IN EFI_HANDLE Image,
806 IN EFI_HANDLE Controller
807 )
808 {
809 ISCSI_DRIVER_DATA *Private;
810 EFI_STATUS Status;
811
812 Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
813 if (Private == NULL) {
814 return NULL;
815 }
816
817 Private->Signature = ISCSI_DRIVER_DATA_SIGNATURE;
818 Private->Image = Image;
819 Private->Controller = Controller;
820 Private->Session = NULL;
821
822 //
823 // Create an event to be signaled when the BS to RT transition is triggerd so
824 // as to abort the iSCSI session.
825 //
826 Status = gBS->CreateEventEx (
827 EVT_NOTIFY_SIGNAL,
828 TPL_CALLBACK,
829 IScsiOnExitBootService,
830 Private,
831 &gEfiEventExitBootServicesGuid,
832 &Private->ExitBootServiceEvent
833 );
834 if (EFI_ERROR (Status)) {
835 FreePool (Private);
836 return NULL;
837 }
838
839 Private->ExtScsiPassThruHandle = NULL;
840 CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
841
842 //
843 // 0 is designated to the TargetId, so use another value for the AdapterId.
844 //
845 Private->ExtScsiPassThruMode.AdapterId = 2;
846 Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
847 Private->ExtScsiPassThruMode.IoAlign = 4;
848 Private->IScsiExtScsiPassThru.Mode = &Private->ExtScsiPassThruMode;
849
850 return Private;
851 }
852
853
854 /**
855 Clean the iSCSI driver data.
856
857 @param[in] Private The iSCSI driver data.
858
859 **/
860 VOID
861 IScsiCleanDriverData (
862 IN ISCSI_DRIVER_DATA *Private
863 )
864 {
865 EFI_STATUS Status;
866
867 if (Private->DevicePath != NULL) {
868 gBS->UninstallProtocolInterface (
869 Private->ExtScsiPassThruHandle,
870 &gEfiDevicePathProtocolGuid,
871 Private->DevicePath
872 );
873
874 FreePool (Private->DevicePath);
875 }
876
877 if (Private->ExtScsiPassThruHandle != NULL) {
878 Status = gBS->UninstallProtocolInterface (
879 Private->ExtScsiPassThruHandle,
880 &gEfiExtScsiPassThruProtocolGuid,
881 &Private->IScsiExtScsiPassThru
882 );
883 if (!EFI_ERROR (Status)) {
884 mPrivate->OneSessionEstablished = FALSE;
885 }
886 }
887
888 gBS->CloseEvent (Private->ExitBootServiceEvent);
889
890 FreePool (Private);
891 }
892
893
894 /**
895 Get the various configuration data.
896
897 @param[in] Private The iSCSI driver data.
898
899 @retval EFI_SUCCESS The configuration data is retrieved.
900 @retval EFI_NOT_FOUND This iSCSI driver is not configured yet.
901
902 **/
903 EFI_STATUS
904 IScsiGetConfigData (
905 IN ISCSI_DRIVER_DATA *Private
906 )
907 {
908 EFI_STATUS Status;
909 CHAR16 MacString[ISCSI_MAX_MAC_STRING_LEN];
910 UINTN Index;
911 ISCSI_NIC_INFO *NicInfo;
912 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
913 ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
914 UINT8 *AttemptConfigOrder;
915 UINTN AttemptConfigOrderSize;
916 CHAR16 IScsiMode[64];
917 CHAR16 IpMode[64];
918
919 //
920 // There should be at least one attempt configured.
921 //
922 AttemptConfigOrder = IScsiGetVariableAndSize (
923 L"AttemptOrder",
924 &gIScsiConfigGuid,
925 &AttemptConfigOrderSize
926 );
927 if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
928 return EFI_NOT_FOUND;
929 }
930
931 //
932 // Get the iSCSI Initiator Name.
933 //
934 mPrivate->InitiatorNameLength = ISCSI_NAME_MAX_SIZE;
935 Status = gIScsiInitiatorName.Get (
936 &gIScsiInitiatorName,
937 &mPrivate->InitiatorNameLength,
938 mPrivate->InitiatorName
939 );
940 if (EFI_ERROR (Status)) {
941 return Status;
942 }
943
944 //
945 // Get the normal configuration.
946 //
947 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
948
949 //
950 // Check whether the attempt exists in AttemptConfig.
951 //
952 AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
953 if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
954 continue;
955 } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
956 //
957 // Check the autoconfig path to see whether it should be retried.
958 //
959 if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
960 AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {
961 if (mPrivate->Ipv6Flag &&
962 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
963 //
964 // Autoconfigure for IP6 already attempted but failed. Do not try again.
965 //
966 continue;
967 } else if (!mPrivate->Ipv6Flag &&
968 AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
969 //
970 // Autoconfigure for IP4 already attempted but failed. Do not try again.
971 //
972 continue;
973 } else {
974 //
975 // Try another approach for this autoconfigure path.
976 //
977 AttemptTmp->AutoConfigureMode =
978 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
979 AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
980 AttemptTmp->SessionConfigData.TargetInfoFromDhcp = TRUE;
981 AttemptTmp->DhcpSuccess = FALSE;
982
983 //
984 // Get some information from the dhcp server.
985 //
986 if (!mPrivate->Ipv6Flag) {
987 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
988 if (!EFI_ERROR (Status)) {
989 AttemptTmp->DhcpSuccess = TRUE;
990 }
991 } else {
992 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
993 if (!EFI_ERROR (Status)) {
994 AttemptTmp->DhcpSuccess = TRUE;
995 }
996 }
997
998 //
999 // Refresh the state of this attempt to NVR.
1000 //
1001 AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1002 UnicodeSPrint (
1003 mPrivate->PortString,
1004 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1005 L"%s%d",
1006 MacString,
1007 (UINTN) AttemptTmp->AttemptConfigIndex
1008 );
1009
1010 gRT->SetVariable (
1011 mPrivate->PortString,
1012 &gEfiIScsiInitiatorNameProtocolGuid,
1013 ISCSI_CONFIG_VAR_ATTR,
1014 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1015 AttemptTmp
1016 );
1017
1018 continue;
1019 }
1020 } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {
1021 //
1022 // Get DHCP information for already added, but failed, attempt.
1023 //
1024 AttemptTmp->DhcpSuccess = FALSE;
1025 if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
1026 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1027 if (!EFI_ERROR (Status)) {
1028 AttemptTmp->DhcpSuccess = TRUE;
1029 }
1030 } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
1031 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1032 if (!EFI_ERROR (Status)) {
1033 AttemptTmp->DhcpSuccess = TRUE;
1034 }
1035 }
1036
1037 //
1038 // Refresh the state of this attempt to NVR.
1039 //
1040 AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1041 UnicodeSPrint (
1042 mPrivate->PortString,
1043 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1044 L"%s%d",
1045 MacString,
1046 (UINTN) AttemptTmp->AttemptConfigIndex
1047 );
1048
1049 gRT->SetVariable (
1050 mPrivate->PortString,
1051 &gEfiIScsiInitiatorNameProtocolGuid,
1052 ISCSI_CONFIG_VAR_ATTR,
1053 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1054 AttemptTmp
1055 );
1056
1057 continue;
1058
1059 } else {
1060 continue;
1061 }
1062 }
1063
1064 //
1065 // This attempt does not exist in AttemptConfig. Try to add a new one.
1066 //
1067
1068 NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
1069 ASSERT (NicInfo != NULL);
1070 IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
1071 UnicodeSPrint (
1072 mPrivate->PortString,
1073 (UINTN) 128,
1074 L"%s%d",
1075 MacString,
1076 (UINTN) AttemptConfigOrder[Index]
1077 );
1078
1079 AttemptConfigData = (ISCSI_ATTEMPT_CONFIG_NVDATA *) GetVariable (
1080 mPrivate->PortString,
1081 &gEfiIScsiInitiatorNameProtocolGuid
1082 );
1083
1084 if (AttemptConfigData == NULL) {
1085 continue;
1086 }
1087
1088 ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
1089
1090 AttemptConfigData->NicIndex = NicInfo->NicIndex;
1091 AttemptConfigData->DhcpSuccess = FALSE;
1092 AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
1093 AttemptConfigData->ValidPath = FALSE;
1094
1095 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1096 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1097 AttemptConfigData->SessionConfigData.TargetInfoFromDhcp = TRUE;
1098
1099 AttemptConfigData->AutoConfigureMode =
1100 (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1101 }
1102
1103 //
1104 // Get some information from dhcp server.
1105 //
1106 if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
1107 AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
1108
1109 if (!mPrivate->Ipv6Flag &&
1110 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
1111 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
1112 Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
1113 if (!EFI_ERROR (Status)) {
1114 AttemptConfigData->DhcpSuccess = TRUE;
1115 }
1116 } else if (mPrivate->Ipv6Flag &&
1117 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
1118 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
1119 Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
1120 if (!EFI_ERROR (Status)) {
1121 AttemptConfigData->DhcpSuccess = TRUE;
1122 }
1123 }
1124
1125 //
1126 // Refresh the state of this attempt to NVR.
1127 //
1128 AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
1129 UnicodeSPrint (
1130 mPrivate->PortString,
1131 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1132 L"%s%d",
1133 MacString,
1134 (UINTN) AttemptConfigData->AttemptConfigIndex
1135 );
1136
1137 gRT->SetVariable (
1138 mPrivate->PortString,
1139 &gEfiIScsiInitiatorNameProtocolGuid,
1140 ISCSI_CONFIG_VAR_ATTR,
1141 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1142 AttemptConfigData
1143 );
1144 }
1145
1146 //
1147 // Update Attempt Help Info.
1148 //
1149
1150 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
1151 UnicodeSPrint (IScsiMode, 64, L"Disabled");
1152 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1153 UnicodeSPrint (IScsiMode, 64, L"Enabled");
1154 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1155 UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
1156 }
1157
1158 if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
1159 UnicodeSPrint (IpMode, 64, L"IP4");
1160 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
1161 UnicodeSPrint (IpMode, 64, L"IP6");
1162 } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1163 UnicodeSPrint (IpMode, 64, L"Autoconfigure");
1164 }
1165
1166 UnicodeSPrint (
1167 mPrivate->PortString,
1168 (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1169 L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1170 MacString,
1171 NicInfo->BusNumber,
1172 NicInfo->DeviceNumber,
1173 NicInfo->FunctionNumber,
1174 IScsiMode,
1175 IpMode
1176 );
1177
1178 AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
1179 mCallbackInfo->RegisteredHandle,
1180 0,
1181 mPrivate->PortString,
1182 NULL
1183 );
1184 ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
1185
1186 //
1187 // Record the attempt in global link list.
1188 //
1189 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1190 mPrivate->AttemptCount++;
1191
1192 if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1193 mPrivate->MpioCount++;
1194 mPrivate->EnableMpio = TRUE;
1195
1196 if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
1197 mPrivate->Krb5MpioCount++;
1198 }
1199 } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1200 mPrivate->SinglePathCount++;
1201 }
1202 }
1203
1204 //
1205 // Reorder the AttemptConfig by the configured order.
1206 //
1207 for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1208 AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1209 if (AttemptConfigData == NULL) {
1210 continue;
1211 }
1212
1213 RemoveEntryList (&AttemptConfigData->Link);
1214 InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1215 }
1216
1217 //
1218 // Update the Main Form.
1219 //
1220 IScsiConfigUpdateAttempt ();
1221
1222 FreePool (AttemptConfigOrder);
1223
1224 //
1225 // There should be at least one attempt configuration.
1226 //
1227 if (!mPrivate->EnableMpio) {
1228 if (mPrivate->SinglePathCount == 0) {
1229 return EFI_NOT_FOUND;
1230 }
1231 mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
1232 }
1233
1234 return EFI_SUCCESS;
1235 }
1236
1237
1238 /**
1239 Get the device path of the iSCSI tcp connection and update it.
1240
1241 @param Session The iSCSI session.
1242
1243 @return The updated device path.
1244 @retval NULL Other errors as indicated.
1245
1246 **/
1247 EFI_DEVICE_PATH_PROTOCOL *
1248 IScsiGetTcpConnDevicePath (
1249 IN ISCSI_SESSION *Session
1250 )
1251 {
1252 ISCSI_CONNECTION *Conn;
1253 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
1254 EFI_STATUS Status;
1255 EFI_DEV_PATH *DPathNode;
1256
1257 if (Session->State != SESSION_STATE_LOGGED_IN) {
1258 return NULL;
1259 }
1260
1261 Conn = NET_LIST_USER_STRUCT_S (
1262 Session->Conns.ForwardLink,
1263 ISCSI_CONNECTION,
1264 Link,
1265 ISCSI_CONNECTION_SIGNATURE
1266 );
1267
1268 Status = gBS->HandleProtocol (
1269 Conn->TcpIo.Handle,
1270 &gEfiDevicePathProtocolGuid,
1271 (VOID **) &DevicePath
1272 );
1273 if (EFI_ERROR (Status)) {
1274 return NULL;
1275 }
1276 //
1277 // Duplicate it.
1278 //
1279 DevicePath = DuplicateDevicePath (DevicePath);
1280 if (DevicePath == NULL) {
1281 return NULL;
1282 }
1283
1284 DPathNode = (EFI_DEV_PATH *) DevicePath;
1285
1286 while (!IsDevicePathEnd (&DPathNode->DevPath)) {
1287 if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
1288 if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
1289 DPathNode->Ipv4.LocalPort = 0;
1290 DPathNode->Ipv4.StaticIpAddress = (BOOLEAN) !Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp;
1291 break;
1292 } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
1293 DPathNode->Ipv6.LocalPort = 0;
1294 DPathNode->Ipv6.StaticIpAddress = (BOOLEAN) !Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp;
1295 break;
1296 }
1297 }
1298
1299 DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
1300 }
1301
1302 return DevicePath;
1303 }
1304
1305
1306 /**
1307 Abort the session when the transition from BS to RT is initiated.
1308
1309 @param[in] Event The event signaled.
1310 @param[in] Context The iSCSI driver data.
1311
1312 **/
1313 VOID
1314 EFIAPI
1315 IScsiOnExitBootService (
1316 IN EFI_EVENT Event,
1317 IN VOID *Context
1318 )
1319 {
1320 ISCSI_DRIVER_DATA *Private;
1321
1322 Private = (ISCSI_DRIVER_DATA *) Context;
1323 gBS->CloseEvent (Private->ExitBootServiceEvent);
1324
1325 if (Private->Session != NULL) {
1326 IScsiSessionAbort (Private->Session);
1327 }
1328 }