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