IScsiMisc.c revision 42f0586d61bc9c7efa47207b71ac52053484c472
1/** @file
2  Miscellaneous routines for iSCSI driver.
3
4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "IScsiImpl.h"
16
17GLOBAL_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**/
28VOID
29IScsiStrTrim (
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**/
81UINT8
82IScsiGetSubnetMaskPrefixLength (
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**/
124EFI_STATUS
125IScsiAsciiStrToLun (
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**/
198VOID
199IScsiLunToUnicodeStr (
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**/
253EFI_STATUS
254IScsiAsciiStrToIp (
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**/
289VOID
290IScsiMacAddrToStr (
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**/
328EFI_STATUS
329IScsiBinToHex (
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**/
377EFI_STATUS
378IScsiHexToBin (
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**/
430UINTN
431IScsiNetNtoi (
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**/
452VOID
453IScsiGenRandom (
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**/
478EFI_STATUS
479IScsiAddNic (
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**/
562EFI_STATUS
563IScsiRemoveNic (
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**/
666ISCSI_NIC_INFO *
667IScsiGetNicInfoByIndex (
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 accroding 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**/
697UINT16
698IScsiGetNICPciLocation (
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**/
756VOID *
757IScsiGetVariableAndSize (
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**/
806ISCSI_DRIVER_DATA *
807IScsiCreateDriverData (
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**/
863VOID
864IScsiCleanDriverData (
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**/
906BOOLEAN
907IScsiDhcpIsConfigured (
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**/
1000EFI_STATUS
1001IScsiGetConfigData (
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->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {
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    }
1201
1202    //
1203    // Get some information from dhcp server.
1204    //
1205    if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
1206        AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
1207
1208      if (!mPrivate->Ipv6Flag &&
1209          (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
1210           AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
1211        Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
1212        if (!EFI_ERROR (Status)) {
1213          AttemptConfigData->DhcpSuccess = TRUE;
1214        }
1215      } else if (mPrivate->Ipv6Flag &&
1216                (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
1217                 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
1218        Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
1219        if (!EFI_ERROR (Status)) {
1220          AttemptConfigData->DhcpSuccess = TRUE;
1221        }
1222      }
1223
1224      //
1225      // Refresh the state of this attempt to NVR.
1226      //
1227      AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
1228      UnicodeSPrint (
1229        mPrivate->PortString,
1230        (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1231        L"%s%d",
1232        MacString,
1233        (UINTN) AttemptConfigData->AttemptConfigIndex
1234        );
1235
1236      gRT->SetVariable (
1237             mPrivate->PortString,
1238             &gEfiIScsiInitiatorNameProtocolGuid,
1239             ISCSI_CONFIG_VAR_ATTR,
1240             sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1241             AttemptConfigData
1242             );
1243    }
1244
1245    //
1246    // Update Attempt Help Info.
1247    //
1248
1249    if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
1250      UnicodeSPrint (IScsiMode, 64, L"Disabled");
1251    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1252      UnicodeSPrint (IScsiMode, 64, L"Enabled");
1253    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1254      UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
1255    }
1256
1257    if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
1258      UnicodeSPrint (IpMode, 64, L"IP4");
1259    } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
1260      UnicodeSPrint (IpMode, 64, L"IP6");
1261    } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1262      UnicodeSPrint (IpMode, 64, L"Autoconfigure");
1263    }
1264
1265    UnicodeSPrint (
1266      mPrivate->PortString,
1267      (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1268      L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1269      MacString,
1270      NicInfo->BusNumber,
1271      NicInfo->DeviceNumber,
1272      NicInfo->FunctionNumber,
1273      IScsiMode,
1274      IpMode
1275      );
1276
1277    AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
1278                                                 mCallbackInfo->RegisteredHandle,
1279                                                 0,
1280                                                 mPrivate->PortString,
1281                                                 NULL
1282                                                 );
1283    ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
1284
1285    //
1286    // Record the attempt in global link list.
1287    //
1288    InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1289    mPrivate->AttemptCount++;
1290
1291    if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1292      mPrivate->MpioCount++;
1293      mPrivate->EnableMpio = TRUE;
1294
1295      if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
1296        mPrivate->Krb5MpioCount++;
1297      }
1298    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1299      mPrivate->SinglePathCount++;
1300    }
1301  }
1302
1303  //
1304  // Reorder the AttemptConfig by the configured order.
1305  //
1306  for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1307    AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1308    if (AttemptConfigData == NULL) {
1309      continue;
1310    }
1311
1312    RemoveEntryList (&AttemptConfigData->Link);
1313    InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1314  }
1315
1316  //
1317  // Update the Main Form.
1318  //
1319  IScsiConfigUpdateAttempt ();
1320
1321  FreePool (AttemptConfigOrder);
1322
1323  //
1324  //  There should be at least one attempt configuration.
1325  //
1326  if (!mPrivate->EnableMpio) {
1327    if (mPrivate->SinglePathCount == 0) {
1328      return EFI_NOT_FOUND;
1329    }
1330    mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
1331  }
1332
1333  return EFI_SUCCESS;
1334}
1335
1336
1337/**
1338  Get the device path of the iSCSI tcp connection and update it.
1339
1340  @param  Session                The iSCSI session.
1341
1342  @return The updated device path.
1343  @retval NULL Other errors as indicated.
1344
1345**/
1346EFI_DEVICE_PATH_PROTOCOL *
1347IScsiGetTcpConnDevicePath (
1348  IN ISCSI_SESSION      *Session
1349  )
1350{
1351  ISCSI_CONNECTION          *Conn;
1352  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
1353  EFI_STATUS                Status;
1354  EFI_DEV_PATH              *DPathNode;
1355  UINTN                     PathLen;
1356
1357  if (Session->State != SESSION_STATE_LOGGED_IN) {
1358    return NULL;
1359  }
1360
1361  Conn = NET_LIST_USER_STRUCT_S (
1362           Session->Conns.ForwardLink,
1363           ISCSI_CONNECTION,
1364           Link,
1365           ISCSI_CONNECTION_SIGNATURE
1366           );
1367
1368  Status = gBS->HandleProtocol (
1369                  Conn->TcpIo.Handle,
1370                  &gEfiDevicePathProtocolGuid,
1371                  (VOID **) &DevicePath
1372                  );
1373  if (EFI_ERROR (Status)) {
1374    return NULL;
1375  }
1376  //
1377  // Duplicate it.
1378  //
1379  DevicePath  = DuplicateDevicePath (DevicePath);
1380  if (DevicePath == NULL) {
1381    return NULL;
1382  }
1383
1384  DPathNode   = (EFI_DEV_PATH *) DevicePath;
1385
1386  while (!IsDevicePathEnd (&DPathNode->DevPath)) {
1387    if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
1388      if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
1389        DPathNode->Ipv4.LocalPort       = 0;
1390
1391        DPathNode->Ipv4.StaticIpAddress =
1392          (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
1393
1394        //
1395        //  Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
1396        //  In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
1397        //  do not exist.
1398        //  In new version of IPv4_DEVICE_PATH, structcure length is 27.
1399        //
1400
1401        PathLen = DevicePathNodeLength (&DPathNode->Ipv4);
1402
1403        if (PathLen == IPv4_NODE_LEN_NEW_VERSIONS) {
1404
1405          IP4_COPY_ADDRESS (
1406            &DPathNode->Ipv4.GatewayIpAddress,
1407            &Session->ConfigData->SessionConfigData.Gateway
1408            );
1409
1410          IP4_COPY_ADDRESS (
1411            &DPathNode->Ipv4.SubnetMask,
1412            &Session->ConfigData->SessionConfigData.SubnetMask
1413            );
1414        }
1415
1416        break;
1417      } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
1418        DPathNode->Ipv6.LocalPort       = 0;
1419
1420        //
1421        //  Add a judgement here to support previous versions of IPv6_DEVICE_PATH.
1422        //  In previous versions of IPv6_DEVICE_PATH, IpAddressOrigin, PrefixLength
1423        //  and GatewayIpAddress do not exist.
1424        //  In new version of IPv6_DEVICE_PATH, structure length is 60, while in
1425        //  old versions, the length is 43.
1426        //
1427
1428        PathLen = DevicePathNodeLength (&DPathNode->Ipv6);
1429
1430        if (PathLen == IPv6_NODE_LEN_NEW_VERSIONS ) {
1431
1432          DPathNode->Ipv6.IpAddressOrigin = 0;
1433          DPathNode->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;
1434          ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
1435        }
1436        else if (PathLen == IPv6_NODE_LEN_OLD_VERSIONS) {
1437
1438          //
1439          //  StaticIPAddress is a field in old versions of IPv6_DEVICE_PATH, while ignored in new
1440          //  version. Set StaticIPAddress through its' offset in old IPv6_DEVICE_PATH.
1441          //
1442          *((UINT8 *)(&DPathNode->Ipv6) + IPv6_OLD_IPADDRESS_OFFSET) =
1443            (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
1444        }
1445
1446        break;
1447      }
1448    }
1449
1450    DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
1451  }
1452
1453  return DevicePath;
1454}
1455
1456
1457/**
1458  Abort the session when the transition from BS to RT is initiated.
1459
1460  @param[in]   Event  The event signaled.
1461  @param[in]  Context The iSCSI driver data.
1462
1463**/
1464VOID
1465EFIAPI
1466IScsiOnExitBootService (
1467  IN EFI_EVENT  Event,
1468  IN VOID       *Context
1469  )
1470{
1471  ISCSI_DRIVER_DATA *Private;
1472
1473  Private = (ISCSI_DRIVER_DATA *) Context;
1474  gBS->CloseEvent (Private->ExitBootServiceEvent);
1475
1476  if (Private->Session != NULL) {
1477    IScsiSessionAbort (Private->Session);
1478  }
1479}
1480
1481/**
1482  Tests whether a controller handle is being managed by IScsi driver.
1483
1484  This function tests whether the driver specified by DriverBindingHandle is
1485  currently managing the controller specified by ControllerHandle.  This test
1486  is performed by evaluating if the the protocol specified by ProtocolGuid is
1487  present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1488  Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1489  If ProtocolGuid is NULL, then ASSERT().
1490
1491  @param  ControllerHandle     A handle for a controller to test.
1492  @param  DriverBindingHandle  Specifies the driver binding handle for the
1493                               driver.
1494  @param  ProtocolGuid         Specifies the protocol that the driver specified
1495                               by DriverBindingHandle opens in its Start()
1496                               function.
1497
1498  @retval EFI_SUCCESS          ControllerHandle is managed by the driver
1499                               specified by DriverBindingHandle.
1500  @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
1501                               specified by DriverBindingHandle.
1502
1503**/
1504EFI_STATUS
1505EFIAPI
1506IScsiTestManagedDevice (
1507  IN  EFI_HANDLE       ControllerHandle,
1508  IN  EFI_HANDLE       DriverBindingHandle,
1509  IN  EFI_GUID         *ProtocolGuid
1510  )
1511{
1512  EFI_STATUS     Status;
1513  VOID           *ManagedInterface;
1514  EFI_HANDLE     NicControllerHandle;
1515
1516  ASSERT (ProtocolGuid != NULL);
1517
1518  NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
1519  if (NicControllerHandle == NULL) {
1520    return EFI_UNSUPPORTED;
1521  }
1522
1523  Status = gBS->OpenProtocol (
1524                  ControllerHandle,
1525                  (EFI_GUID *) ProtocolGuid,
1526                  &ManagedInterface,
1527                  DriverBindingHandle,
1528                  NicControllerHandle,
1529                  EFI_OPEN_PROTOCOL_BY_DRIVER
1530                  );
1531  if (!EFI_ERROR (Status)) {
1532    gBS->CloseProtocol (
1533           ControllerHandle,
1534           (EFI_GUID *) ProtocolGuid,
1535           DriverBindingHandle,
1536           NicControllerHandle
1537           );
1538    return EFI_UNSUPPORTED;
1539  }
1540
1541  if (Status != EFI_ALREADY_STARTED) {
1542    return EFI_UNSUPPORTED;
1543  }
1544
1545  return EFI_SUCCESS;
1546}
1547