IScsiMisc.c revision 18b24f924f06f2345c0410d145d14e1a9a500dc8
1/** @file
2  Miscellaneous routines for iSCSI driver.
3
4Copyright (c) 2004 - 2014, 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(AttemptTmp == NULL || EFI_ERROR (Status)) {
957      continue;
958    }
959
960    ASSERT (AttemptConfigOrder[Index] == AttemptTmp->AttemptConfigIndex);
961
962    if (AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
963      FreePool (AttemptTmp);
964      continue;
965    }
966
967    if (AttemptTmp->SessionConfigData.IpMode != IP_MODE_AUTOCONFIG &&
968        AttemptTmp->SessionConfigData.IpMode != ((IpVersion == IP_VERSION_4) ? IP_MODE_IP4 : IP_MODE_IP6)) {
969      FreePool (AttemptTmp);
970      continue;
971    }
972
973    if(AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG ||
974       AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp == TRUE ||
975       AttemptTmp->SessionConfigData.TargetInfoFromDhcp == TRUE) {
976      FreePool (AttemptTmp);
977      FreePool (AttemptConfigOrder);
978      return TRUE;
979    }
980
981    FreePool (AttemptTmp);
982  }
983
984  FreePool (AttemptConfigOrder);
985  return FALSE;
986}
987
988/**
989  Get the various configuration data.
990
991  @param[in]  Private   The iSCSI driver data.
992
993  @retval EFI_SUCCESS            The configuration data is retrieved.
994  @retval EFI_NOT_FOUND          This iSCSI driver is not configured yet.
995
996**/
997EFI_STATUS
998IScsiGetConfigData (
999  IN ISCSI_DRIVER_DATA  *Private
1000  )
1001{
1002  EFI_STATUS                  Status;
1003  CHAR16                      MacString[ISCSI_MAX_MAC_STRING_LEN];
1004  UINTN                       Index;
1005  ISCSI_NIC_INFO              *NicInfo;
1006  ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptConfigData;
1007  ISCSI_ATTEMPT_CONFIG_NVDATA *AttemptTmp;
1008  UINT8                       *AttemptConfigOrder;
1009  UINTN                       AttemptConfigOrderSize;
1010  CHAR16                      IScsiMode[64];
1011  CHAR16                      IpMode[64];
1012
1013  //
1014  // There should be at least one attempt configured.
1015  //
1016  AttemptConfigOrder = IScsiGetVariableAndSize (
1017                         L"AttemptOrder",
1018                         &gIScsiConfigGuid,
1019                         &AttemptConfigOrderSize
1020                         );
1021  if (AttemptConfigOrder == NULL || AttemptConfigOrderSize == 0) {
1022    return EFI_NOT_FOUND;
1023  }
1024
1025  //
1026  // Get the iSCSI Initiator Name.
1027  //
1028  mPrivate->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;
1029  Status = gIScsiInitiatorName.Get (
1030                                 &gIScsiInitiatorName,
1031                                 &mPrivate->InitiatorNameLength,
1032                                 mPrivate->InitiatorName
1033                                 );
1034  if (EFI_ERROR (Status)) {
1035    return Status;
1036  }
1037
1038  //
1039  // Get the normal configuration.
1040  //
1041  for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1042
1043    //
1044    // Check whether the attempt exists in AttemptConfig.
1045    //
1046    AttemptTmp = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1047    if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled == ISCSI_DISABLED) {
1048      continue;
1049    } else if (AttemptTmp != NULL && AttemptTmp->SessionConfigData.Enabled != ISCSI_DISABLED) {
1050      //
1051      // Check the autoconfig path to see whether it should be retried.
1052      //
1053      if (AttemptTmp->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG &&
1054          AttemptTmp->AutoConfigureMode != IP_MODE_AUTOCONFIG_SUCCESS) {
1055        if (mPrivate->Ipv6Flag &&
1056            AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6) {
1057          //
1058          // Autoconfigure for IP6 already attempted but failed. Do not try again.
1059          //
1060          continue;
1061        } else if (!mPrivate->Ipv6Flag &&
1062                   AttemptTmp->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4) {
1063          //
1064          // Autoconfigure for IP4  already attempted but failed. Do not try again.
1065          //
1066          continue;
1067        } else {
1068          //
1069          // Try another approach for this autoconfigure path.
1070          //
1071          AttemptTmp->AutoConfigureMode =
1072            (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1073          AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1074          AttemptTmp->SessionConfigData.TargetInfoFromDhcp    = TRUE;
1075          AttemptTmp->DhcpSuccess                             = FALSE;
1076
1077          //
1078          // Get some information from the dhcp server.
1079          //
1080          if (!mPrivate->Ipv6Flag) {
1081            Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1082            if (!EFI_ERROR (Status)) {
1083              AttemptTmp->DhcpSuccess = TRUE;
1084            }
1085          } else {
1086            Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1087            if (!EFI_ERROR (Status)) {
1088              AttemptTmp->DhcpSuccess = TRUE;
1089            }
1090          }
1091
1092          //
1093          // Refresh the state of this attempt to NVR.
1094          //
1095          AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1096          UnicodeSPrint (
1097            mPrivate->PortString,
1098            (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1099            L"%s%d",
1100            MacString,
1101            (UINTN) AttemptTmp->AttemptConfigIndex
1102            );
1103
1104          gRT->SetVariable (
1105                 mPrivate->PortString,
1106                 &gEfiIScsiInitiatorNameProtocolGuid,
1107                 ISCSI_CONFIG_VAR_ATTR,
1108                 sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1109                 AttemptTmp
1110                 );
1111
1112          continue;
1113        }
1114      } else if (AttemptTmp->SessionConfigData.InitiatorInfoFromDhcp && !AttemptTmp->ValidPath) {
1115        //
1116        // Get DHCP information for already added, but failed, attempt.
1117        //
1118        AttemptTmp->DhcpSuccess = FALSE;
1119        if (!mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP4)) {
1120          Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptTmp);
1121          if (!EFI_ERROR (Status)) {
1122            AttemptTmp->DhcpSuccess = TRUE;
1123          }
1124        } else if (mPrivate->Ipv6Flag && (AttemptTmp->SessionConfigData.IpMode == IP_MODE_IP6)) {
1125          Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptTmp);
1126          if (!EFI_ERROR (Status)) {
1127            AttemptTmp->DhcpSuccess = TRUE;
1128          }
1129        }
1130
1131        //
1132        // Refresh the state of this attempt to NVR.
1133        //
1134        AsciiStrToUnicodeStr (AttemptTmp->MacString, MacString);
1135        UnicodeSPrint (
1136          mPrivate->PortString,
1137          (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1138          L"%s%d",
1139          MacString,
1140          (UINTN) AttemptTmp->AttemptConfigIndex
1141          );
1142
1143        gRT->SetVariable (
1144               mPrivate->PortString,
1145               &gEfiIScsiInitiatorNameProtocolGuid,
1146               ISCSI_CONFIG_VAR_ATTR,
1147               sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1148               AttemptTmp
1149               );
1150
1151        continue;
1152
1153      } else {
1154        continue;
1155      }
1156    }
1157
1158    //
1159    // This attempt does not exist in AttemptConfig. Try to add a new one.
1160    //
1161
1162    NicInfo = IScsiGetNicInfoByIndex (mPrivate->CurrentNic);
1163    ASSERT (NicInfo != NULL);
1164    IScsiMacAddrToStr (&NicInfo->PermanentAddress, NicInfo->HwAddressSize, NicInfo->VlanId, MacString);
1165    UnicodeSPrint (
1166      mPrivate->PortString,
1167      (UINTN) 128,
1168      L"%s%d",
1169      MacString,
1170      (UINTN) AttemptConfigOrder[Index]
1171      );
1172
1173    GetVariable2 (
1174                 mPrivate->PortString,
1175                 &gEfiIScsiInitiatorNameProtocolGuid,
1176                 (VOID**)&AttemptConfigData,
1177                 NULL
1178                 );
1179
1180    if (AttemptConfigData == NULL) {
1181      continue;
1182    }
1183
1184    ASSERT (AttemptConfigOrder[Index] == AttemptConfigData->AttemptConfigIndex);
1185
1186    AttemptConfigData->NicIndex      = NicInfo->NicIndex;
1187    AttemptConfigData->DhcpSuccess   = FALSE;
1188    AttemptConfigData->ValidiBFTPath = (BOOLEAN) (mPrivate->EnableMpio ? TRUE : FALSE);
1189    AttemptConfigData->ValidPath     = FALSE;
1190
1191    if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1192      AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp = TRUE;
1193      AttemptConfigData->SessionConfigData.TargetInfoFromDhcp    = TRUE;
1194
1195      AttemptConfigData->AutoConfigureMode =
1196        (UINT8) (mPrivate->Ipv6Flag ? IP_MODE_AUTOCONFIG_IP6 : IP_MODE_AUTOCONFIG_IP4);
1197    }
1198
1199    //
1200    // Get some information from dhcp server.
1201    //
1202    if (AttemptConfigData->SessionConfigData.Enabled != ISCSI_DISABLED &&
1203        AttemptConfigData->SessionConfigData.InitiatorInfoFromDhcp) {
1204
1205      if (!mPrivate->Ipv6Flag &&
1206          (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4 ||
1207           AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP4)) {
1208        Status = IScsiDoDhcp (Private->Image, Private->Controller, AttemptConfigData);
1209        if (!EFI_ERROR (Status)) {
1210          AttemptConfigData->DhcpSuccess = TRUE;
1211        }
1212      } else if (mPrivate->Ipv6Flag &&
1213                (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6 ||
1214                 AttemptConfigData->AutoConfigureMode == IP_MODE_AUTOCONFIG_IP6)) {
1215        Status = IScsiDoDhcp6 (Private->Image, Private->Controller, AttemptConfigData);
1216        if (!EFI_ERROR (Status)) {
1217          AttemptConfigData->DhcpSuccess = TRUE;
1218        }
1219      }
1220
1221      //
1222      // Refresh the state of this attempt to NVR.
1223      //
1224      AsciiStrToUnicodeStr (AttemptConfigData->MacString, MacString);
1225      UnicodeSPrint (
1226        mPrivate->PortString,
1227        (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1228        L"%s%d",
1229        MacString,
1230        (UINTN) AttemptConfigData->AttemptConfigIndex
1231        );
1232
1233      gRT->SetVariable (
1234             mPrivate->PortString,
1235             &gEfiIScsiInitiatorNameProtocolGuid,
1236             ISCSI_CONFIG_VAR_ATTR,
1237             sizeof (ISCSI_ATTEMPT_CONFIG_NVDATA),
1238             AttemptConfigData
1239             );
1240    }
1241
1242    //
1243    // Update Attempt Help Info.
1244    //
1245
1246    if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_DISABLED) {
1247      UnicodeSPrint (IScsiMode, 64, L"Disabled");
1248    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1249      UnicodeSPrint (IScsiMode, 64, L"Enabled");
1250    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1251      UnicodeSPrint (IScsiMode, 64, L"Enabled for MPIO");
1252    }
1253
1254    if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP4) {
1255      UnicodeSPrint (IpMode, 64, L"IP4");
1256    } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_IP6) {
1257      UnicodeSPrint (IpMode, 64, L"IP6");
1258    } else if (AttemptConfigData->SessionConfigData.IpMode == IP_MODE_AUTOCONFIG) {
1259      UnicodeSPrint (IpMode, 64, L"Autoconfigure");
1260    }
1261
1262    UnicodeSPrint (
1263      mPrivate->PortString,
1264      (UINTN) ISCSI_NAME_IFR_MAX_SIZE,
1265      L"MAC: %s, PFA: Bus %d | Dev %d | Func %d, iSCSI mode: %s, IP version: %s",
1266      MacString,
1267      NicInfo->BusNumber,
1268      NicInfo->DeviceNumber,
1269      NicInfo->FunctionNumber,
1270      IScsiMode,
1271      IpMode
1272      );
1273
1274    AttemptConfigData->AttemptTitleHelpToken = HiiSetString (
1275                                                 mCallbackInfo->RegisteredHandle,
1276                                                 0,
1277                                                 mPrivate->PortString,
1278                                                 NULL
1279                                                 );
1280    ASSERT (AttemptConfigData->AttemptTitleHelpToken != 0);
1281
1282    //
1283    // Record the attempt in global link list.
1284    //
1285    InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1286    mPrivate->AttemptCount++;
1287
1288    if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED_FOR_MPIO) {
1289      mPrivate->MpioCount++;
1290      mPrivate->EnableMpio = TRUE;
1291
1292      if (AttemptConfigData->AuthenticationType == ISCSI_AUTH_TYPE_KRB) {
1293        mPrivate->Krb5MpioCount++;
1294      }
1295    } else if (AttemptConfigData->SessionConfigData.Enabled == ISCSI_ENABLED) {
1296      mPrivate->SinglePathCount++;
1297    }
1298  }
1299
1300  //
1301  // Reorder the AttemptConfig by the configured order.
1302  //
1303  for (Index = 0; Index < AttemptConfigOrderSize / sizeof (UINT8); Index++) {
1304    AttemptConfigData = IScsiConfigGetAttemptByConfigIndex (AttemptConfigOrder[Index]);
1305    if (AttemptConfigData == NULL) {
1306      continue;
1307    }
1308
1309    RemoveEntryList (&AttemptConfigData->Link);
1310    InsertTailList (&mPrivate->AttemptConfigs, &AttemptConfigData->Link);
1311  }
1312
1313  //
1314  // Update the Main Form.
1315  //
1316  IScsiConfigUpdateAttempt ();
1317
1318  FreePool (AttemptConfigOrder);
1319
1320  //
1321  //  There should be at least one attempt configuration.
1322  //
1323  if (!mPrivate->EnableMpio) {
1324    if (mPrivate->SinglePathCount == 0) {
1325      return EFI_NOT_FOUND;
1326    }
1327    mPrivate->ValidSinglePathCount = mPrivate->SinglePathCount;
1328  }
1329
1330  return EFI_SUCCESS;
1331}
1332
1333
1334/**
1335  Get the device path of the iSCSI tcp connection and update it.
1336
1337  @param  Session                The iSCSI session.
1338
1339  @return The updated device path.
1340  @retval NULL Other errors as indicated.
1341
1342**/
1343EFI_DEVICE_PATH_PROTOCOL *
1344IScsiGetTcpConnDevicePath (
1345  IN ISCSI_SESSION      *Session
1346  )
1347{
1348  ISCSI_CONNECTION          *Conn;
1349  EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
1350  EFI_STATUS                Status;
1351  EFI_DEV_PATH              *DPathNode;
1352
1353  if (Session->State != SESSION_STATE_LOGGED_IN) {
1354    return NULL;
1355  }
1356
1357  Conn = NET_LIST_USER_STRUCT_S (
1358           Session->Conns.ForwardLink,
1359           ISCSI_CONNECTION,
1360           Link,
1361           ISCSI_CONNECTION_SIGNATURE
1362           );
1363
1364  Status = gBS->HandleProtocol (
1365                  Conn->TcpIo.Handle,
1366                  &gEfiDevicePathProtocolGuid,
1367                  (VOID **) &DevicePath
1368                  );
1369  if (EFI_ERROR (Status)) {
1370    return NULL;
1371  }
1372  //
1373  // Duplicate it.
1374  //
1375  DevicePath  = DuplicateDevicePath (DevicePath);
1376  if (DevicePath == NULL) {
1377    return NULL;
1378  }
1379
1380  DPathNode   = (EFI_DEV_PATH *) DevicePath;
1381
1382  while (!IsDevicePathEnd (&DPathNode->DevPath)) {
1383    if (DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) {
1384      if (!Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP) {
1385        DPathNode->Ipv4.LocalPort       = 0;
1386
1387        DPathNode->Ipv4.StaticIpAddress =
1388          (BOOLEAN) (!Session->ConfigData->SessionConfigData.InitiatorInfoFromDhcp);
1389
1390        IP4_COPY_ADDRESS (
1391          &DPathNode->Ipv4.GatewayIpAddress,
1392          &Session->ConfigData->SessionConfigData.Gateway
1393          );
1394
1395        IP4_COPY_ADDRESS (
1396          &DPathNode->Ipv4.SubnetMask,
1397          &Session->ConfigData->SessionConfigData.SubnetMask
1398          );
1399        break;
1400      } else if (Conn->Ipv6Flag && DevicePathSubType (&DPathNode->DevPath) == MSG_IPv6_DP) {
1401        DPathNode->Ipv6.LocalPort       = 0;
1402        DPathNode->Ipv6.IpAddressOrigin = 0;
1403        DPathNode->Ipv6.PrefixLength    = IP6_PREFIX_LENGTH;
1404        ZeroMem (&DPathNode->Ipv6.GatewayIpAddress, sizeof (EFI_IPv6_ADDRESS));
1405        break;
1406      }
1407    }
1408
1409    DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
1410  }
1411
1412  return DevicePath;
1413}
1414
1415
1416/**
1417  Abort the session when the transition from BS to RT is initiated.
1418
1419  @param[in]   Event  The event signaled.
1420  @param[in]  Context The iSCSI driver data.
1421
1422**/
1423VOID
1424EFIAPI
1425IScsiOnExitBootService (
1426  IN EFI_EVENT  Event,
1427  IN VOID       *Context
1428  )
1429{
1430  ISCSI_DRIVER_DATA *Private;
1431
1432  Private = (ISCSI_DRIVER_DATA *) Context;
1433  gBS->CloseEvent (Private->ExitBootServiceEvent);
1434
1435  if (Private->Session != NULL) {
1436    IScsiSessionAbort (Private->Session);
1437  }
1438}
1439
1440/**
1441  Tests whether a controller handle is being managed by IScsi driver.
1442
1443  This function tests whether the driver specified by DriverBindingHandle is
1444  currently managing the controller specified by ControllerHandle.  This test
1445  is performed by evaluating if the the protocol specified by ProtocolGuid is
1446  present on ControllerHandle and is was opened by DriverBindingHandle and Nic
1447  Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
1448  If ProtocolGuid is NULL, then ASSERT().
1449
1450  @param  ControllerHandle     A handle for a controller to test.
1451  @param  DriverBindingHandle  Specifies the driver binding handle for the
1452                               driver.
1453  @param  ProtocolGuid         Specifies the protocol that the driver specified
1454                               by DriverBindingHandle opens in its Start()
1455                               function.
1456
1457  @retval EFI_SUCCESS          ControllerHandle is managed by the driver
1458                               specified by DriverBindingHandle.
1459  @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
1460                               specified by DriverBindingHandle.
1461
1462**/
1463EFI_STATUS
1464EFIAPI
1465IScsiTestManagedDevice (
1466  IN  EFI_HANDLE       ControllerHandle,
1467  IN  EFI_HANDLE       DriverBindingHandle,
1468  IN  EFI_GUID         *ProtocolGuid
1469  )
1470{
1471  EFI_STATUS     Status;
1472  VOID           *ManagedInterface;
1473  EFI_HANDLE     NicControllerHandle;
1474
1475  ASSERT (ProtocolGuid != NULL);
1476
1477  NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
1478  if (NicControllerHandle == NULL) {
1479    return EFI_UNSUPPORTED;
1480  }
1481
1482  Status = gBS->OpenProtocol (
1483                  ControllerHandle,
1484                  (EFI_GUID *) ProtocolGuid,
1485                  &ManagedInterface,
1486                  DriverBindingHandle,
1487                  NicControllerHandle,
1488                  EFI_OPEN_PROTOCOL_BY_DRIVER
1489                  );
1490  if (!EFI_ERROR (Status)) {
1491    gBS->CloseProtocol (
1492           ControllerHandle,
1493           (EFI_GUID *) ProtocolGuid,
1494           DriverBindingHandle,
1495           NicControllerHandle
1496           );
1497    return EFI_UNSUPPORTED;
1498  }
1499
1500  if (Status != EFI_ALREADY_STARTED) {
1501    return EFI_UNSUPPORTED;
1502  }
1503
1504  return EFI_SUCCESS;
1505}
1506