1 /** @file
2   Miscellaneous routines for iSCSI driver.
3 
4 Copyright (c) 2004 - 2015, 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
IScsiStrTrim(IN OUT CHAR16 * Str,IN CHAR16 CharC)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
IScsiGetSubnetMaskPrefixLength(IN EFI_IPv4_ADDRESS * SubnetMask)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
IScsiAsciiStrToLun(IN CHAR8 * Str,OUT UINT8 * Lun)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
IScsiLunToUnicodeStr(IN UINT8 * Lun,OUT CHAR16 * Str)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       CopyMem (TempStr, L"0-", sizeof (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   // Remove the last '-'
228   //
229   ASSERT (StrLen(Str) >= 1);
230   Str[StrLen (Str) - 1] = 0;
231 
232   for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
233     if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
234       Str[Index - 1] = 0;
235     } else {
236       break;
237     }
238   }
239 }
240 
241 /**
242   Convert the formatted IP address into the binary IP address.
243 
244   @param[in]   Str               The UNICODE string.
245   @param[in]   IpMode            Indicates whether the IP address is v4 or v6.
246   @param[out]  Ip                The storage to return the ASCII string.
247 
248   @retval EFI_SUCCESS            The binary IP address is returned in Ip.
249   @retval EFI_INVALID_PARAMETER  The IP string is malformatted or IpMode is
250                                  invalid.
251 
252 **/
253 EFI_STATUS
IScsiAsciiStrToIp(IN CHAR8 * Str,IN UINT8 IpMode,OUT EFI_IP_ADDRESS * Ip)254 IScsiAsciiStrToIp (
255   IN  CHAR8             *Str,
256   IN  UINT8             IpMode,
257   OUT EFI_IP_ADDRESS    *Ip
258   )
259 {
260   EFI_STATUS            Status;
261 
262   if (IpMode == IP_MODE_IP4 || IpMode == IP_MODE_AUTOCONFIG_IP4) {
263     return NetLibAsciiStrToIp4 (Str, &Ip->v4);
264 
265   } else if (IpMode == IP_MODE_IP6 || IpMode == IP_MODE_AUTOCONFIG_IP6) {
266     return NetLibAsciiStrToIp6 (Str, &Ip->v6);
267 
268   } else if (IpMode == IP_MODE_AUTOCONFIG) {
269     Status = NetLibAsciiStrToIp4 (Str, &Ip->v4);
270     if (!EFI_ERROR (Status)) {
271       return Status;
272     }
273     return NetLibAsciiStrToIp6 (Str, &Ip->v6);
274 
275   }
276 
277   return EFI_INVALID_PARAMETER;
278 }
279 
280 /**
281   Convert the mac address into a hexadecimal encoded "-" seperated string.
282 
283   @param[in]  Mac     The mac address.
284   @param[in]  Len     Length in bytes of the mac address.
285   @param[in]  VlanId  VLAN ID of the network device.
286   @param[out] Str     The storage to return the mac string.
287 
288 **/
289 VOID
IScsiMacAddrToStr(IN EFI_MAC_ADDRESS * Mac,IN UINT32 Len,IN UINT16 VlanId,OUT CHAR16 * Str)290 IScsiMacAddrToStr (
291   IN  EFI_MAC_ADDRESS  *Mac,
292   IN  UINT32           Len,
293   IN  UINT16           VlanId,
294   OUT CHAR16           *Str
295   )
296 {
297   UINT32  Index;
298   CHAR16  *String;
299 
300   for (Index = 0; Index < Len; Index++) {
301     Str[3 * Index]      = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];
302     Str[3 * Index + 1]  = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];
303     Str[3 * Index + 2]  = L':';
304   }
305 
306   String = &Str[3 * Index - 1] ;
307   if (VlanId != 0) {
308     String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
309   }
310 
311   *String = L'\0';
312 }
313 
314 /**
315   Convert the binary encoded buffer into a hexadecimal encoded string.
316 
317   @param[in]       BinBuffer   The buffer containing the binary data.
318   @param[in]       BinLength   Length of the binary buffer.
319   @param[in, out]  HexStr      Pointer to the string.
320   @param[in, out]  HexLength   The length of the string.
321 
322   @retval EFI_SUCCESS          The binary data is converted to the hexadecimal string
323                                and the length of the string is updated.
324   @retval EFI_BUFFER_TOO_SMALL The string is too small.
325   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
326 
327 **/
328 EFI_STATUS
IScsiBinToHex(IN UINT8 * BinBuffer,IN UINT32 BinLength,IN OUT CHAR8 * HexStr,IN OUT UINT32 * HexLength)329 IScsiBinToHex (
330   IN     UINT8  *BinBuffer,
331   IN     UINT32 BinLength,
332   IN OUT CHAR8  *HexStr,
333   IN OUT UINT32 *HexLength
334   )
335 {
336   UINTN Index;
337 
338   if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
339     return EFI_INVALID_PARAMETER;
340   }
341 
342   if (((*HexLength) - 3) < BinLength * 2) {
343     *HexLength = BinLength * 2 + 3;
344     return EFI_BUFFER_TOO_SMALL;
345   }
346 
347   *HexLength = BinLength * 2 + 3;
348   //
349   // Prefix for Hex String.
350   //
351   HexStr[0] = '0';
352   HexStr[1] = 'x';
353 
354   for (Index = 0; Index < BinLength; Index++) {
355     HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];
356     HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0xf];
357   }
358 
359   HexStr[Index * 2 + 2] = '\0';
360 
361   return EFI_SUCCESS;
362 }
363 
364 
365 /**
366   Convert the hexadecimal string into a binary encoded buffer.
367 
368   @param[in, out]  BinBuffer   The binary buffer.
369   @param[in, out]  BinLength   Length of the binary buffer.
370   @param[in]       HexStr      The hexadecimal string.
371 
372   @retval EFI_SUCCESS          The hexadecimal string is converted into a binary
373                                encoded buffer.
374   @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
375 
376 **/
377 EFI_STATUS
IScsiHexToBin(IN OUT UINT8 * BinBuffer,IN OUT UINT32 * BinLength,IN CHAR8 * HexStr)378 IScsiHexToBin (
379   IN OUT UINT8  *BinBuffer,
380   IN OUT UINT32 *BinLength,
381   IN     CHAR8  *HexStr
382   )
383 {
384   UINTN   Index;
385   UINTN   Length;
386   UINT8   Digit;
387   CHAR8   TemStr[2];
388 
389   ZeroMem (TemStr, sizeof (TemStr));
390 
391   //
392   // Find out how many hex characters the string has.
393   //
394   if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
395     HexStr += 2;
396   }
397 
398   Length = AsciiStrLen (HexStr);
399 
400   for (Index = 0; Index < Length; Index ++) {
401     TemStr[0] = HexStr[Index];
402     Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
403     if (Digit == 0 && TemStr[0] != '0') {
404       //
405       // Invalid Lun Char.
406       //
407       break;
408     }
409     if ((Index & 1) == 0) {
410       BinBuffer [Index/2] = Digit;
411     } else {
412       BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
413     }
414   }
415 
416   *BinLength = (UINT32) ((Index + 1)/2);
417 
418   return EFI_SUCCESS;
419 }
420 
421 
422 /**
423   Convert the decimal-constant string or hex-constant string into a numerical value.
424 
425   @param[in] Str                    String in decimal or hex.
426 
427   @return The numerical value.
428 
429 **/
430 UINTN
IScsiNetNtoi(IN CHAR8 * Str)431 IScsiNetNtoi (
432   IN     CHAR8  *Str
433   )
434 {
435   if ((Str[0] == '0') && ((Str[1] == 'x') || (Str[1] == 'X'))) {
436     Str += 2;
437 
438     return AsciiStrHexToUintn (Str);
439   }
440 
441   return AsciiStrDecimalToUintn (Str);
442 }
443 
444 
445 /**
446   Generate random numbers.
447 
448   @param[in, out]  Rand       The buffer to contain random numbers.
449   @param[in]       RandLength The length of the Rand buffer.
450 
451 **/
452 VOID
IScsiGenRandom(IN OUT UINT8 * Rand,IN UINTN RandLength)453 IScsiGenRandom (
454   IN OUT UINT8  *Rand,
455   IN     UINTN  RandLength
456   )
457 {
458   UINT32  Random;
459 
460   while (RandLength > 0) {
461     Random  = NET_RANDOM (NetRandomInitSeed ());
462     *Rand++ = (UINT8) (Random);
463     RandLength--;
464   }
465 }
466 
467 
468 /**
469   Record the NIC info in global structure.
470 
471   @param[in]  Controller         The handle of the controller.
472 
473   @retval EFI_SUCCESS            The operation is completed.
474   @retval EFI_OUT_OF_RESOURCES   Do not have sufficient resources to finish this
475                                  operation.
476 
477 **/
478 EFI_STATUS
IScsiAddNic(IN EFI_HANDLE Controller)479 IScsiAddNic (
480   IN EFI_HANDLE  Controller
481   )
482 {
483   EFI_STATUS                  Status;
484   ISCSI_NIC_INFO              *NicInfo;
485   LIST_ENTRY                  *Entry;
486   EFI_MAC_ADDRESS             MacAddr;
487   UINTN                       HwAddressSize;
488   UINT16                      VlanId;
489 
490   //
491   // Get MAC address of this network device.
492   //
493   Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
494   if (EFI_ERROR (Status)) {
495     return Status;
496   }
497 
498   //
499   // Get VLAN ID of this network device.
500   //
501   VlanId = NetLibGetVlanId (Controller);
502 
503   //
504   // Check whether the NIC info already exists. Return directly if so.
505   //
506   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
507     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
508     if (NicInfo->HwAddressSize == HwAddressSize &&
509         CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
510         NicInfo->VlanId == VlanId) {
511       mPrivate->CurrentNic = NicInfo->NicIndex;
512       return EFI_SUCCESS;
513     }
514 
515     if (mPrivate->MaxNic < NicInfo->NicIndex) {
516       mPrivate->MaxNic = NicInfo->NicIndex;
517     }
518   }
519 
520   //
521   // Record the NIC info in private structure.
522   //
523   NicInfo = AllocateZeroPool (sizeof (ISCSI_NIC_INFO));
524   if (NicInfo == NULL) {
525     return EFI_OUT_OF_RESOURCES;
526   }
527 
528   CopyMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize);
529   NicInfo->HwAddressSize  = (UINT32) HwAddressSize;
530   NicInfo->VlanId         = VlanId;
531   NicInfo->NicIndex       = (UINT8) (mPrivate->MaxNic + 1);
532   mPrivate->MaxNic        = NicInfo->NicIndex;
533 
534   //
535   // Get the PCI location.
536   //
537   IScsiGetNICPciLocation (
538     Controller,
539     &NicInfo->BusNumber,
540     &NicInfo->DeviceNumber,
541     &NicInfo->FunctionNumber
542     );
543 
544   InsertTailList (&mPrivate->NicInfoList, &NicInfo->Link);
545   mPrivate->NicCount++;
546 
547   mPrivate->CurrentNic = NicInfo->NicIndex;
548   return EFI_SUCCESS;
549 }
550 
551 
552 /**
553   Delete the recorded NIC info from global structure. Also delete corresponding
554   attempts.
555 
556   @param[in]  Controller         The handle of the controller.
557 
558   @retval EFI_SUCCESS            The operation is completed.
559   @retval EFI_NOT_FOUND          The NIC info to be deleted is not recorded.
560 
561 **/
562 EFI_STATUS
IScsiRemoveNic(IN EFI_HANDLE Controller)563 IScsiRemoveNic (
564   IN EFI_HANDLE  Controller
565   )
566 {
567   EFI_STATUS                  Status;
568   ISCSI_NIC_INFO              *NicInfo;
569   LIST_ENTRY                  *Entry;
570   LIST_ENTRY                  *NextEntry;
571   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
572   ISCSI_NIC_INFO              *ThisNic;
573   EFI_MAC_ADDRESS             MacAddr;
574   UINTN                       HwAddressSize;
575   UINT16                      VlanId;
576 
577   //
578   // Get MAC address of this network device.
579   //
580   Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
581   if (EFI_ERROR (Status)) {
582     return Status;
583   }
584 
585   //
586   // Get VLAN ID of this network device.
587   //
588   VlanId = NetLibGetVlanId (Controller);
589 
590   //
591   // Check whether the NIC information exists.
592   //
593   ThisNic = NULL;
594 
595   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
596     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
597     if (NicInfo->HwAddressSize == HwAddressSize &&
598         CompareMem (&NicInfo->PermanentAddress, MacAddr.Addr, HwAddressSize) == 0 &&
599         NicInfo->VlanId == VlanId) {
600 
601       ThisNic = NicInfo;
602       break;
603     }
604   }
605 
606   if (ThisNic == NULL) {
607     return EFI_NOT_FOUND;
608   }
609 
610   mPrivate->CurrentNic = ThisNic->NicIndex;
611 
612   RemoveEntryList (&ThisNic->Link);
613   FreePool (ThisNic);
614   mPrivate->NicCount--;
615 
616   //
617   // Remove all attempts related to this NIC.
618   //
619   NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, &mPrivate->AttemptConfigs) {
620     AttemptConfigData = NET_LIST_USER_STRUCT (Entry, ISCSI_ATTEMPT_CONFIG_NVDATA, Link);
621     if (AttemptConfigData->NicIndex == mPrivate->CurrentNic) {
622       RemoveEntryList (&AttemptConfigData->Link);
623       mPrivate->AttemptCount--;
624 
625       if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO && mPrivate->MpioCount > 0) {
626         if (--mPrivate->MpioCount == 0) {
627           mPrivate->EnableMpio = FALSE;
628         }
629 
630         if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB && mPrivate->Krb5MpioCount > 0) {
631           mPrivate->Krb5MpioCount--;
632         }
633 
634       } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED && mPrivate->SinglePathCount > 0) {
635         mPrivate->SinglePathCount--;
636 
637         if (mPrivate->ValidSinglePathCount > 0) {
638           mPrivate->ValidSinglePathCount--;
639         }
640       }
641 
642       FreePool (AttemptConfigData);
643     }
644   }
645 
646   //
647   // Free attempt is created but not saved to system.
648   //
649   if (mPrivate->NewAttempt != NULL) {
650     FreePool (mPrivate->NewAttempt);
651     mPrivate->NewAttempt = NULL;
652   }
653 
654   return EFI_SUCCESS;
655 }
656 
657 
658 /**
659   Get the recorded NIC info from global structure by the Index.
660 
661   @param[in]  NicIndex          The index indicates the position of NIC info.
662 
663   @return Pointer to the NIC info, or NULL if not found.
664 
665 **/
666 ISCSI_NIC_INFO *
IScsiGetNicInfoByIndex(IN UINT8 NicIndex)667 IScsiGetNicInfoByIndex (
668   IN UINT8      NicIndex
669   )
670 {
671   LIST_ENTRY        *Entry;
672   ISCSI_NIC_INFO    *NicInfo;
673 
674   NET_LIST_FOR_EACH (Entry, &mPrivate->NicInfoList) {
675     NicInfo = NET_LIST_USER_STRUCT (Entry, ISCSI_NIC_INFO, Link);
676     if (NicInfo->NicIndex == NicIndex) {
677       return NicInfo;
678     }
679   }
680 
681   return NULL;
682 }
683 
684 
685 /**
686   Get the NIC's PCI location and return it according to the composited
687   format defined in iSCSI Boot Firmware Table.
688 
689   @param[in]   Controller        The handle of the controller.
690   @param[out]  Bus               The bus number.
691   @param[out]  Device            The device number.
692   @param[out]  Function          The function number.
693 
694   @return      The composited representation of the NIC PCI location.
695 
696 **/
697 UINT16
IScsiGetNICPciLocation(IN EFI_HANDLE Controller,OUT UINTN * Bus,OUT UINTN * Device,OUT UINTN * Function)698 IScsiGetNICPciLocation (
699   IN EFI_HANDLE  Controller,
700   OUT UINTN      *Bus,
701   OUT UINTN      *Device,
702   OUT UINTN      *Function
703   )
704 {
705   EFI_STATUS                Status;
706   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
707   EFI_HANDLE                PciIoHandle;
708   EFI_PCI_IO_PROTOCOL       *PciIo;
709   UINTN                     Segment;
710 
711   Status = gBS->HandleProtocol (
712                   Controller,
713                   &gEfiDevicePathProtocolGuid,
714                   (VOID **) &DevicePath
715                   );
716   if (EFI_ERROR (Status)) {
717     return 0;
718   }
719 
720   Status = gBS->LocateDevicePath (
721                   &gEfiPciIoProtocolGuid,
722                   &DevicePath,
723                   &PciIoHandle
724                   );
725   if (EFI_ERROR (Status)) {
726     return 0;
727   }
728 
729   Status = gBS->HandleProtocol (PciIoHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
730   if (EFI_ERROR (Status)) {
731     return 0;
732   }
733 
734   Status = PciIo->GetLocation (PciIo, &Segment, Bus, Device, Function);
735   if (EFI_ERROR (Status)) {
736     return 0;
737   }
738 
739   return (UINT16) ((*Bus << 8) | (*Device << 3) | *Function);
740 }
741 
742 
743 /**
744   Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
745   buffer, and the size of the buffer. If failure, return NULL.
746 
747   @param[in]   Name                   String part of EFI variable name.
748   @param[in]   VendorGuid             GUID part of EFI variable name.
749   @param[out]  VariableSize           Returns the size of the EFI variable that was read.
750 
751   @return Dynamically allocated memory that contains a copy of the EFI variable.
752   @return Caller is responsible freeing the buffer.
753   @retval NULL                   Variable was not read.
754 
755 **/
756 VOID *
IScsiGetVariableAndSize(IN CHAR16 * Name,IN EFI_GUID * VendorGuid,OUT UINTN * VariableSize)757 IScsiGetVariableAndSize (
758   IN  CHAR16              *Name,
759   IN  EFI_GUID            *VendorGuid,
760   OUT UINTN               *VariableSize
761   )
762 {
763   EFI_STATUS  Status;
764   UINTN       BufferSize;
765   VOID        *Buffer;
766 
767   Buffer = NULL;
768 
769   //
770   // Pass in a zero size buffer to find the required buffer size.
771   //
772   BufferSize  = 0;
773   Status      = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
774   if (Status == EFI_BUFFER_TOO_SMALL) {
775     //
776     // Allocate the buffer to return
777     //
778     Buffer = AllocateZeroPool (BufferSize);
779     if (Buffer == NULL) {
780       return NULL;
781     }
782     //
783     // Read variable into the allocated buffer.
784     //
785     Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
786     if (EFI_ERROR (Status)) {
787       BufferSize = 0;
788     }
789   }
790 
791   *VariableSize = BufferSize;
792   return Buffer;
793 }
794 
795 
796 /**
797   Create the iSCSI driver data.
798 
799   @param[in] Image      The handle of the driver image.
800   @param[in] Controller The handle of the controller.
801 
802   @return The iSCSI driver data created.
803   @retval NULL Other errors as indicated.
804 
805 **/
806 ISCSI_DRIVER_DATA *
IScsiCreateDriverData(IN EFI_HANDLE Image,IN EFI_HANDLE Controller)807 IScsiCreateDriverData (
808   IN EFI_HANDLE  Image,
809   IN EFI_HANDLE  Controller
810   )
811 {
812   ISCSI_DRIVER_DATA *Private;
813   EFI_STATUS        Status;
814 
815   Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
816   if (Private == NULL) {
817     return NULL;
818   }
819 
820   Private->Signature  = ISCSI_DRIVER_DATA_SIGNATURE;
821   Private->Image      = Image;
822   Private->Controller = Controller;
823   Private->Session    = NULL;
824 
825   //
826   // Create an event to be signaled when the BS to RT transition is triggerd so
827   // as to abort the iSCSI session.
828   //
829   Status = gBS->CreateEventEx (
830                   EVT_NOTIFY_SIGNAL,
831                   TPL_CALLBACK,
832                   IScsiOnExitBootService,
833                   Private,
834                   &gEfiEventExitBootServicesGuid,
835                   &Private->ExitBootServiceEvent
836                   );
837   if (EFI_ERROR (Status)) {
838     FreePool (Private);
839     return NULL;
840   }
841 
842   Private->ExtScsiPassThruHandle = NULL;
843   CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
844 
845   //
846   // 0 is designated to the TargetId, so use another value for the AdapterId.
847   //
848   Private->ExtScsiPassThruMode.AdapterId  = 2;
849   Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
850   Private->ExtScsiPassThruMode.IoAlign    = 4;
851   Private->IScsiExtScsiPassThru.Mode      = &Private->ExtScsiPassThruMode;
852 
853   return Private;
854 }
855 
856 
857 /**
858   Clean the iSCSI driver data.
859 
860   @param[in]  Private The iSCSI driver data.
861 
862 **/
863 VOID
IScsiCleanDriverData(IN ISCSI_DRIVER_DATA * Private)864 IScsiCleanDriverData (
865   IN ISCSI_DRIVER_DATA  *Private
866   )
867 {
868   EFI_STATUS            Status;
869 
870   if (Private->DevicePath != NULL) {
871     gBS->UninstallProtocolInterface (
872            Private->ExtScsiPassThruHandle,
873            &gEfiDevicePathProtocolGuid,
874            Private->DevicePath
875            );
876 
877     FreePool (Private->DevicePath);
878   }
879 
880   if (Private->ExtScsiPassThruHandle != NULL) {
881     Status = gBS->UninstallProtocolInterface (
882                     Private->ExtScsiPassThruHandle,
883                     &gEfiExtScsiPassThruProtocolGuid,
884                     &Private->IScsiExtScsiPassThru
885                     );
886     if (!EFI_ERROR (Status)) {
887       mPrivate->OneSessionEstablished = FALSE;
888     }
889   }
890 
891   gBS->CloseEvent (Private->ExitBootServiceEvent);
892 
893   FreePool (Private);
894 }
895 
896 /**
897   Check wheather the Controller handle is configured to use DHCP protocol.
898 
899   @param[in]  Controller           The handle of the controller.
900   @param[in]  IpVersion            IP_VERSION_4 or IP_VERSION_6.
901 
902   @retval TRUE                     The handle of the controller need the Dhcp protocol.
903   @retval FALSE                    The handle of the controller does not need the Dhcp protocol.
904 
905 **/
906 BOOLEAN
IScsiDhcpIsConfigured(IN EFI_HANDLE Controller,IN UINT8 IpVersion)907 IScsiDhcpIsConfigured (
908   IN EFI_HANDLE  Controller,
909   IN UINT8       IpVersion
910   )
911 {
912   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
913   UINT8                       *AttemptConfigOrder;
914   UINTN                       AttemptConfigOrderSize;
915   UINTN                       Index;
916   EFI_STATUS                  Status;
917   EFI_MAC_ADDRESS             MacAddr;
918   UINTN                       HwAddressSize;
919   UINT16                      VlanId;
920   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
921   CHAR16                      AttemptName[ISCSI_NAME_IFR_MAX_SIZE];
922 
923   AttemptConfigOrder = IScsiGetVariableAndSize (
924                          L"AttemptOrder",
925                          &gIScsiConfigGuid,
926                          &AttemptConfigOrderSize
927                          );
928   if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
929     return FALSE;
930   }
931 
932   //
933   // Get MAC address of this network device.
934   //
935   Status = NetLibGetMacAddress (Controller, &MacAddr, &HwAddressSize);
936   if(EFI_ERROR (Status)) {
937     return FALSE;
938   }
939   //
940   // Get VLAN ID of this network device.
941   //
942   VlanId = NetLibGetVlanId (Controller);
943   IScsiMacAddrToStr (&MacAddr, (UINT32) HwAddressSize, VlanId, MacString);
944 
945   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
946     UnicodeSPrint (
947       AttemptName,
948       (UINTN) 128,
949       L"%s%d",
950       MacString,
951       (UINTN) AttemptConfigOrder[Index]
952       );
953     Status = GetVariable2 (
954                AttemptName,
955                &gEfiIScsiInitiatorNameProtocolGuid,
956                (VOID**)&AttemptTmp,
957                NULL
958                );
959     if(AttemptTmp == NULL || EFI_ERROR (Status)) {
960       continue;
961     }
962 
963     ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);
964 
965     if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
966       FreePool (AttemptTmp);
967       continue;
968     }
969 
970     if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG &&
971         AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) {
972       FreePool (AttemptTmp);
973       continue;
974     }
975 
976     if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG ||
977        AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE ||
978        AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) {
979       FreePool (AttemptTmp);
980       FreePool (AttemptConfigOrder);
981       return TRUE;
982     }
983 
984     FreePool (AttemptTmp);
985   }
986 
987   FreePool (AttemptConfigOrder);
988   return FALSE;
989 }
990 
991 /**
992   Get the various configuration data.
993 
994   @param[in]  Private   The iSCSI driver data.
995 
996   @retval EFI_SUCCESS            The configuration data is retrieved.
997   @retval EFI_NOT_FOUND          This iSCSI driver is not configured yet.
998 
999 **/
1000 EFI_STATUS
IScsiGetConfigData(IN ISCSI_DRIVER_DATA * Private)1001 IScsiGetConfigData (
1002   IN ISCSI_DRIVER_DATA  *Private
1003   )
1004 {
1005   EFI_STATUS                  Status;
1006   CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
1007   UINTN                       Index;
1008   ISCSI_NIC_INFO              *NicInfo;
1009   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
1010   ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
1011   UINT8                       *AttemptConfigOrder;
1012   UINTN                       AttemptConfigOrderSize;
1013   CHAR16                      IScsiMode[64];
1014   CHAR16                      IpMode[64];
1015 
1016   //
1017   // There should be at least one attempt configured.
1018   //
1019   AttemptConfigOrder = IScsiGetVariableAndSize (
1020                          L"AttemptOrder",
1021                          &gIScsiConfigGuid,
1022                          &AttemptConfigOrderSize
1023                          );
1024   if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
1025     return EFI_NOT_FOUND;
1026   }
1027 
1028   //
1029   // Get the iSCSI Initiator Name.
1030   //
1031   mPrivate->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;
1032   Status = gIScsiInitiatorName.Get (
1033                                  &gIScsiInitiatorName,
1034                                  &mPrivate->InitiatorNameLength,
1035                                  mPrivate->InitiatorName
1036                                  );
1037   if (EFI_ERROR (Status)) {
1038     return Status;
1039   }
1040 
1041   //
1042   // Get the normal configuration.
1043   //
1044   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1045 
1046     //
1047     // Check whether the attempt exists in AttemptConfig.
1048     //
1049     AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1050     if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
1051       continue;
1052     } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
1053       //
1054       // Check the autoconfig path to see whether it should be retried.
1055       //
1056       if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
1057           !AttemptTmp->AutoConfigureSuccess) {
1058         if (mPrivate->Ipv6Flag &&
1059             AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
1060           //
1061           // Autoconfigure for IP6 already attempted but failed. Do not try again.
1062           //
1063           continue;
1064         } else if (!mPrivate->Ipv6Flag &&
1065                    AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
1066           //
1067           // Autoconfigure for IP4  already attempted but failed. Do not try again.
1068           //
1069           continue;
1070         } else {
1071           //
1072           // Try another approach for this autoconfigure path.
1073           //
1074           AttemptTmp->AutoConfigureMode =
1075             (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1076           AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1077           AttemptTmp->SessionConfigData.TargetInfoFromDhcp    = TRUE;
1078           AttemptTmp->DhcpSuccess                             = FALSE;
1079 
1080           //
1081           // Get some information from the dhcp server.
1082           //
1083           if (!mPrivate->Ipv6Flag) {
1084             Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1085             if (!EFI_ERROR (Status)) {
1086               AttemptTmp->DhcpSuccess = TRUE;
1087             }
1088           } else {
1089             Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1090             if (!EFI_ERROR (Status)) {
1091               AttemptTmp->DhcpSuccess = TRUE;
1092             }
1093           }
1094 
1095           //
1096           // Refresh the state of this attempt to NVR.
1097           //
1098           AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1099           UnicodeSPrint (
1100             mPrivate->PortString,
1101             (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1102             L"%s%d",
1103             MacString,
1104             (UINTN) AttemptTmp->AttemptConfigIndex
1105             );
1106 
1107           gRT->SetVariable (
1108                  mPrivate->PortString,
1109                  &gEfiIScsiInitiatorNameProtocolGuid,
1110                  ISCSI_CONFIG_VAR_ATTR,
1111                  sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1112                  AttemptTmp
1113                  );
1114 
1115           continue;
1116         }
1117       } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {
1118         //
1119         // Get DHCP information for already added, but failed, attempt.
1120         //
1121         AttemptTmp->DhcpSuccess = FALSE;
1122         if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
1123           Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1124           if (!EFI_ERROR (Status)) {
1125             AttemptTmp->DhcpSuccess = TRUE;
1126           }
1127         } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
1128           Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1129           if (!EFI_ERROR (Status)) {
1130             AttemptTmp->DhcpSuccess = TRUE;
1131           }
1132         }
1133 
1134         //
1135         // Refresh the state of this attempt to NVR.
1136         //
1137         AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1138         UnicodeSPrint (
1139           mPrivate->PortString,
1140           (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1141           L"%s%d",
1142           MacString,
1143           (UINTN) AttemptTmp->AttemptConfigIndex
1144           );
1145 
1146         gRT->SetVariable (
1147                mPrivate->PortString,
1148                &gEfiIScsiInitiatorNameProtocolGuid,
1149                ISCSI_CONFIG_VAR_ATTR,
1150                sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1151                AttemptTmp
1152                );
1153 
1154         continue;
1155 
1156       } else {
1157         continue;
1158       }
1159     }
1160 
1161     //
1162     // This attempt does not exist in AttemptConfig. Try to add a new one.
1163     //
1164 
1165     NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
1166     ASSERT (NicInfo != NULL);
1167     IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
1168     UnicodeSPrint (
1169       mPrivate->PortString,
1170       (UINTN) 128,
1171       L"%s%d",
1172       MacString,
1173       (UINTN) AttemptConfigOrder[Index]
1174       );
1175 
1176     GetVariable2 (
1177                  mPrivate->PortString,
1178                  &gEfiIScsiInitiatorNameProtocolGuid,
1179                  (VOID**)&AttemptConfigData,
1180                  NULL
1181                  );
1182 
1183     if (AttemptConfigData == NULL) {
1184       continue;
1185     }
1186 
1187     ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
1188 
1189     AttemptConfigData->NicIndex      = NicInfo->NicIndex;
1190     AttemptConfigData->DhcpSuccess   = FALSE;
1191     AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
1192     AttemptConfigData->ValidPath     = FALSE;
1193 
1194     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1195       AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1196       AttemptConfigData->SessionConfigData.TargetInfoFromDhcp    = TRUE;
1197 
1198       AttemptConfigData->AutoConfigureMode =
1199         (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1200       AttemptConfigData->AutoConfigureSuccess = FALSE;
1201     }
1202 
1203     //
1204     // Get some information from dhcp server.
1205     //
1206     if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
1207         AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
1208 
1209       if (!mPrivate->Ipv6Flag &&
1210           (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
1211            AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
1212         Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
1213         if (!EFI_ERROR (Status)) {
1214           AttemptConfigData->DhcpSuccess = TRUE;
1215         }
1216       } else if (mPrivate->Ipv6Flag &&
1217                 (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
1218                  AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
1219         Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
1220         if (!EFI_ERROR (Status)) {
1221           AttemptConfigData->DhcpSuccess = TRUE;
1222         }
1223       }
1224 
1225       //
1226       // Refresh the state of this attempt to NVR.
1227       //
1228       AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
1229       UnicodeSPrint (
1230         mPrivate->PortString,
1231         (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1232         L"%s%d",
1233         MacString,
1234         (UINTN) AttemptConfigData->AttemptConfigIndex
1235         );
1236 
1237       gRT->SetVariable (
1238              mPrivate->PortString,
1239              &gEfiIScsiInitiatorNameProtocolGuid,
1240              ISCSI_CONFIG_VAR_ATTR,
1241              sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1242              AttemptConfigData
1243              );
1244     }
1245 
1246     //
1247     // Update Attempt Help Info.
1248     //
1249 
1250     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
1251       UnicodeSPrint (IScsiMode, 64, L"Disabled");
1252     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1253       UnicodeSPrint (IScsiMode, 64, L"Enabled");
1254     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1255       UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
1256     }
1257 
1258     if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
1259       UnicodeSPrint (IpMode, 64, L"IP4");
1260     } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
1261       UnicodeSPrint (IpMode, 64, L"IP6");
1262     } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1263       UnicodeSPrint (IpMode, 64, L"Autoconfigure");
1264     }
1265 
1266     UnicodeSPrint (
1267       mPrivate->PortString,
1268       (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1269       L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1270       MacString,
1271       NicInfo->BusNumber,
1272       NicInfo->DeviceNumber,
1273       NicInfo->FunctionNumber,
1274       IScsiMode,
1275       IpMode
1276       );
1277 
1278     AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
1279                                                  mCallbackInfo->RegisteredHandle,
1280                                                  0,
1281                                                  mPrivate->PortString,
1282                                                  NULL
1283                                                  );
1284     ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
1285 
1286     //
1287     // Record the attempt in global link list.
1288     //
1289     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1290     mPrivate->AttemptCount++;
1291 
1292     if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1293       mPrivate->MpioCount++;
1294       mPrivate->EnableMpio = TRUE;
1295 
1296       if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
1297         mPrivate->Krb5MpioCount++;
1298       }
1299     } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1300       mPrivate->SinglePathCount++;
1301     }
1302   }
1303 
1304   //
1305   // Reorder the AttemptConfig by the configured order.
1306   //
1307   for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1308     AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1309     if (AttemptConfigData == NULL) {
1310       continue;
1311     }
1312 
1313     RemoveEntryList (&AttemptConfigData->Link);
1314     InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1315   }
1316 
1317   //
1318   // Update the Main Form.
1319   //
1320   IScsiConfigUpdateAttempt ();
1321 
1322   FreePool (AttemptConfigOrder);
1323 
1324   //
1325   //  There should be at least one attempt configuration.
1326   //
1327   if (!mPrivate->EnableMpio) {
1328     if (mPrivate->SinglePathCount == 0) {
1329       return EFI_NOT_FOUND;
1330     }
1331     mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
1332   }
1333 
1334   return EFI_SUCCESS;
1335 }
1336 
1337 
1338 /**
1339   Get the device path of the iSCSI tcp connection and update it.
1340 
1341   @param  Session                The iSCSI session.
1342 
1343   @return The updated device path.
1344   @retval NULL Other errors as indicated.
1345 
1346 **/
1347 EFI_DEVICE_PATH_PROTOCOL *
IScsiGetTcpConnDevicePath(IN ISCSI_SESSION * Session)1348 IScsiGetTcpConnDevicePath (
1349   IN ISCSI_SESSION      *Session
1350   )
1351 {
1352   ISCSI_CONNECTION          *Conn;
1353   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
1354   EFI_STATUS                Status;
1355   EFI_DEV_PATH              *DPathNode;
1356   UINTN                     PathLen;
1357 
1358   if (Session->State != SESSION_STATE_LOGGED_IN) {
1359     return NULL;
1360   }
1361 
1362   Conn = NET_LIST_USER_STRUCT_S (
1363            Session->Conns.ForwardLink,
1364            ISCSI_CONNECTION,
1365            Link,
1366            ISCSI_CONNECTION_SIGNATURE
1367            );
1368 
1369   Status = gBS->HandleProtocol (
1370                   Conn->TcpIo.Handle,
1371                   &gEfiDevicePathProtocolGuid,
1372                   (VOID **) &DevicePath
1373                   );
1374   if (EFI_ERROR (Status)) {
1375     return NULL;
1376   }
1377   //
1378   // Duplicate it.
1379   //
1380   DevicePath  = DuplicateDevicePath (DevicePath);
1381   if (DevicePath == NULL) {
1382     return NULL;
1383   }
1384 
1385   DPathNode   = (EFI_DEV_PATH *) DevicePath;
1386 
1387   while (!IsDevicePathEnd (&DPathNode->DevPath)) {
1388     if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
1389       if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
1390         DPathNode->Ipv4.LocalPort       = 0;
1391 
1392         DPathNode->Ipv4.StaticIpAddress =
1393           (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
1394 
1395         //
1396         //  Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
1397         //  In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
1398         //  do not exist.
1399         //  In new version of IPv4_DEVICE_PATH, structcure length is 27.
1400         //
1401 
1402         PathLen = DevicePathNodeLength (&DPathNode->Ipv4);
1403 
1404         if (PathLen == IP4_NODE_LEN_NEW_VERSIONS) {
1405 
1406           IP4_COPY_ADDRESS (
1407             &DPathNode->Ipv4.GatewayIpAddress,
1408             &Session->ConfigData->SessionConfigData.Gateway
1409             );
1410 
1411           IP4_COPY_ADDRESS (
1412             &DPathNode->Ipv4.SubnetMask,
1413             &Session->ConfigData->SessionConfigData.SubnetMask
1414             );
1415         }
1416 
1417         break;
1418       } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
1419         DPathNode->Ipv6.LocalPort       = 0;
1420 
1421         //
1422         //  Add a judgement here to support previous versions of IPv6_DEVICE_PATH.
1423         //  In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength
1424         //  and GatewayIpAddress do not exist.
1425         //  In new version of IPv6_DEVICE_PATH, structure length is 60, while in
1426         //  old versions, the length is 43.
1427         //
1428 
1429         PathLen = DevicePathNodeLength (&DPathNode->Ipv6);
1430 
1431         if (PathLen == IP6_NODE_LEN_NEW_VERSIONS ) {
1432 
1433           DPathNode->Ipv6.IpAddressOrigin = 0;
1434           DPathNode->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;
1435           ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
1436         }
1437         else if (PathLen == IP6_NODE_LEN_OLD_VERSIONS) {
1438 
1439           //
1440           //  StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new
1441           //  version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH.
1442           //
1443           *((UINT8 *)(&DPathNode->Ipv6) + IP6_OLD_IPADDRESS_OFFSET) =
1444             (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
1445         }
1446 
1447         break;
1448       }
1449     }
1450 
1451     DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
1452   }
1453 
1454   return DevicePath;
1455 }
1456 
1457 
1458 /**
1459   Abort the session when the transition from BS to RT is initiated.
1460 
1461   @param[in]   Event  The event signaled.
1462   @param[in]  Context The iSCSI driver data.
1463 
1464 **/
1465 VOID
1466 EFIAPI
IScsiOnExitBootService(IN EFI_EVENT Event,IN VOID * Context)1467 IScsiOnExitBootService (
1468   IN EFI_EVENT  Event,
1469   IN VOID       *Context
1470   )
1471 {
1472   ISCSI_DRIVER_DATA *Private;
1473 
1474   Private = (ISCSI_DRIVER_DATA *) Context;
1475   gBS->CloseEvent (Private->ExitBootServiceEvent);
1476 
1477   if (Private->Session != NULL) {
1478     IScsiSessionAbort (Private->Session);
1479   }
1480 }
1481 
1482 /**
1483   Tests whether a controller handle is being managed by IScsi driver.
1484 
1485   This function tests whether the driver specified by DriverBindingHandle is
1486   currently managing the controller specified by ControllerHandle.  This test
1487   is performed by evaluating if the the protocol specified by ProtocolGuid is
1488   present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1489   Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1490   If ProtocolGuid is NULL, then ASSERT().
1491 
1492   @param  ControllerHandle     A handle for a controller to test.
1493   @param  DriverBindingHandle  Specifies the driver binding handle for the
1494                                driver.
1495   @param  ProtocolGuid         Specifies the protocol that the driver specified
1496                                by DriverBindingHandle opens in its Start()
1497                                function.
1498 
1499   @retval EFI_SUCCESS          ControllerHandle is managed by the driver
1500                                specified by DriverBindingHandle.
1501   @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
1502                                specified by DriverBindingHandle.
1503 
1504 **/
1505 EFI_STATUS
1506 EFIAPI
IScsiTestManagedDevice(IN EFI_HANDLE ControllerHandle,IN EFI_HANDLE DriverBindingHandle,IN EFI_GUID * ProtocolGuid)1507 IScsiTestManagedDevice (
1508   IN  EFI_HANDLE       ControllerHandle,
1509   IN  EFI_HANDLE       DriverBindingHandle,
1510   IN  EFI_GUID         *ProtocolGuid
1511   )
1512 {
1513   EFI_STATUS     Status;
1514   VOID           *ManagedInterface;
1515   EFI_HANDLE     NicControllerHandle;
1516 
1517   ASSERT (ProtocolGuid != NULL);
1518 
1519   NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
1520   if (NicControllerHandle == NULL) {
1521     return EFI_UNSUPPORTED;
1522   }
1523 
1524   Status = gBS->OpenProtocol (
1525                   ControllerHandle,
1526                   (EFI_GUID *) ProtocolGuid,
1527                   &ManagedInterface,
1528                   DriverBindingHandle,
1529                   NicControllerHandle,
1530                   EFI_OPEN_PROTOCOL_BY_DRIVER
1531                   );
1532   if (!EFI_ERROR (Status)) {
1533     gBS->CloseProtocol (
1534            ControllerHandle,
1535            (EFI_GUID *) ProtocolGuid,
1536            DriverBindingHandle,
1537            NicControllerHandle
1538            );
1539     return EFI_UNSUPPORTED;
1540   }
1541 
1542   if (Status != EFI_ALREADY_STARTED) {
1543     return EFI_UNSUPPORTED;
1544   }
1545 
1546   return EFI_SUCCESS;
1547 }
1548