Home | History | Annotate | Download | only in IScsiDxe
      1 /** @file
      2   Miscellaneous routines for iSCSI driver.
      3 
      4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "IScsiImpl.h"
     16 
     17 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8  IScsiHexString[] = "0123456789ABCDEFabcdef";
     18 
     19 /**
     20   Removes (trims) specified leading and trailing characters from a string.
     21 
     22   @param[in, out]  Str  Pointer to the null-terminated string to be trimmed. On return,
     23                         Str will hold the trimmed string.
     24 
     25   @param[in]      CharC Character will be trimmed from str.
     26 **/
     27 VOID
     28 StrTrim (
     29   IN OUT CHAR16   *Str,
     30   IN     CHAR16   CharC
     31   )
     32 {
     33   CHAR16  *Pointer1;
     34   CHAR16  *Pointer2;
     35 
     36   if (*Str == 0) {
     37     return;
     38   }
     39 
     40   //
     41   // Trim off the leading and trailing characters c
     42   //
     43   for (Pointer1 = Str; (*Pointer1 != 0) && (*Pointer1 == CharC); Pointer1++) {
     44     ;
     45   }
     46 
     47   Pointer2 = Str;
     48   if (Pointer2 == Pointer1) {
     49     while (*Pointer1 != 0) {
     50       Pointer2++;
     51       Pointer1++;
     52     }
     53   } else {
     54     while (*Pointer1 != 0) {
     55     *Pointer2 = *Pointer1;
     56     Pointer1++;
     57     Pointer2++;
     58     }
     59     *Pointer2 = 0;
     60   }
     61 
     62 
     63   for (Pointer1 = Str + StrLen(Str) - 1; Pointer1 >= Str && *Pointer1 == CharC; Pointer1--) {
     64     ;
     65   }
     66   if  (Pointer1 !=  Str + StrLen(Str) - 1) {
     67     *(Pointer1 + 1) = 0;
     68   }
     69 }
     70 
     71 /**
     72   Calculate the prefix length of the IPv4 subnet mask.
     73 
     74   @param[in]  SubnetMask The IPv4 subnet mask.
     75 
     76   @return The prefix length of the subnet mask.
     77   @retval 0 Other errors as indicated.
     78 **/
     79 UINT8
     80 IScsiGetSubnetMaskPrefixLength (
     81   IN EFI_IPv4_ADDRESS  *SubnetMask
     82   )
     83 {
     84   UINT8   Len;
     85   UINT32  ReverseMask;
     86 
     87   //
     88   // The SubnetMask is in network byte order.
     89   //
     90   ReverseMask = (SubnetMask->Addr[0] << 24) | (SubnetMask->Addr[1] << 16) | (SubnetMask->Addr[2] << 8) | (SubnetMask->Addr[3]);
     91 
     92   //
     93   // Reverse it.
     94   //
     95   ReverseMask = ~ReverseMask;
     96 
     97   if ((ReverseMask & (ReverseMask + 1)) != 0) {
     98     return 0;
     99   }
    100 
    101   Len = 0;
    102 
    103   while (ReverseMask != 0) {
    104     ReverseMask = ReverseMask >> 1;
    105     Len++;
    106   }
    107 
    108   return (UINT8) (32 - Len);
    109 }
    110 
    111 /**
    112   Convert the hexadecimal encoded LUN string into the 64-bit LUN.
    113 
    114   @param[in]   Str             The hexadecimal encoded LUN string.
    115   @param[out]  Lun             Storage to return the 64-bit LUN.
    116 
    117   @retval EFI_SUCCESS           The 64-bit LUN is stored in Lun.
    118   @retval EFI_INVALID_PARAMETER The string is malformatted.
    119 **/
    120 EFI_STATUS
    121 IScsiAsciiStrToLun (
    122   IN  CHAR8  *Str,
    123   OUT UINT8  *Lun
    124   )
    125 {
    126   UINTN   Index, IndexValue, IndexNum, SizeStr;
    127   CHAR8   TemStr[2];
    128   UINT8   TemValue;
    129   UINT16  Value[4];
    130 
    131   ZeroMem (Lun, 8);
    132   ZeroMem (TemStr, 2);
    133   ZeroMem ((UINT8 *) Value, sizeof (Value));
    134   SizeStr    = AsciiStrLen (Str);
    135   IndexValue = 0;
    136   IndexNum   = 0;
    137 
    138   for (Index = 0; Index < SizeStr; Index ++) {
    139     TemStr[0] = Str[Index];
    140     TemValue = (UINT8) AsciiStrHexToUint64 (TemStr);
    141     if (TemValue == 0 && TemStr[0] != '0') {
    142       if ((TemStr[0] != '-') || (IndexNum == 0)) {
    143         //
    144         // Invalid Lun Char
    145         //
    146         return EFI_INVALID_PARAMETER;
    147       }
    148     }
    149 
    150     if ((TemValue == 0) && (TemStr[0] == '-')) {
    151       //
    152       // Next Lun value
    153       //
    154       if (++IndexValue >= 4) {
    155         //
    156         // Max 4 Lun value
    157         //
    158         return EFI_INVALID_PARAMETER;
    159       }
    160       //
    161       // Restart str index for the next lun value
    162       //
    163       IndexNum = 0;
    164       continue;
    165     }
    166 
    167     if (++IndexNum > 4) {
    168       //
    169       // Each Lun Str can't exceed size 4, because it will be as UINT16 value
    170       //
    171       return EFI_INVALID_PARAMETER;
    172     }
    173 
    174     //
    175     // Combine UINT16 value
    176     //
    177     Value[IndexValue] = (UINT16) ((Value[IndexValue] << 4) + TemValue);
    178   }
    179 
    180   for (Index = 0; Index <= IndexValue; Index ++) {
    181     *((UINT16 *) &Lun[Index * 2]) =  HTONS (Value[Index]);
    182   }
    183 
    184   return EFI_SUCCESS;
    185 }
    186 
    187 /**
    188   Convert the 64-bit LUN into the hexadecimal encoded LUN string.
    189 
    190   @param[in]   Lun The 64-bit LUN.
    191   @param[out]  Str The storage to return the hexadecimal encoded LUN string.
    192 **/
    193 VOID
    194 IScsiLunToUnicodeStr (
    195   IN UINT8    *Lun,
    196   OUT CHAR16  *Str
    197   )
    198 {
    199   UINTN   Index;
    200   CHAR16  *TempStr;
    201 
    202   TempStr = Str;
    203 
    204   for (Index = 0; Index < 4; Index++) {
    205 
    206     if ((Lun[2 * Index] | Lun[2 * Index + 1]) == 0) {
    207       CopyMem(TempStr, L"0-", sizeof (L"0-"));
    208     } else {
    209       TempStr[0]  = (CHAR16) IScsiHexString[Lun[2 * Index] >> 4];
    210       TempStr[1]  = (CHAR16) IScsiHexString[Lun[2 * Index] & 0x0F];
    211       TempStr[2]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] >> 4];
    212       TempStr[3]  = (CHAR16) IScsiHexString[Lun[2 * Index + 1] & 0x0F];
    213       TempStr[4]  = L'-';
    214       TempStr[5]  = 0;
    215 
    216       StrTrim (TempStr, L'0');
    217     }
    218 
    219     TempStr += StrLen (TempStr);
    220   }
    221 
    222   ASSERT (StrLen(Str) >= 1);
    223   Str[StrLen (Str) - 1] = 0;
    224 
    225   for (Index = StrLen (Str) - 1; Index > 1; Index = Index - 2) {
    226     if ((Str[Index] == L'0') && (Str[Index - 1] == L'-')) {
    227       Str[Index - 1] = 0;
    228     } else {
    229       break;
    230     }
    231   }
    232 }
    233 
    234 /**
    235   Convert the ASCII string into a UNICODE string.
    236 
    237   @param[in]   Source      The ASCII string.
    238   @param[out]  Destination The storage to return the UNICODE string.
    239 
    240   @return CHAR16 *         Pointer to the UNICODE string.
    241 **/
    242 CHAR16 *
    243 IScsiAsciiStrToUnicodeStr (
    244   IN  CHAR8   *Source,
    245   OUT CHAR16  *Destination
    246   )
    247 {
    248   ASSERT (Destination != NULL);
    249   ASSERT (Source != NULL);
    250 
    251   while (*Source != '\0') {
    252     *(Destination++) = (CHAR16) *(Source++);
    253   }
    254 
    255   *Destination = '\0';
    256 
    257   return Destination;
    258 }
    259 
    260 /**
    261   Convert the UNICODE string into an ASCII string.
    262 
    263   @param[in]  Source       The UNICODE string.
    264   @param[out] Destination  The storage to return the ASCII string.
    265 
    266   @return CHAR8 *          Pointer to the ASCII string.
    267 **/
    268 CHAR8 *
    269 IScsiUnicodeStrToAsciiStr (
    270   IN  CHAR16  *Source,
    271   OUT CHAR8   *Destination
    272   )
    273 {
    274   ASSERT (Destination != NULL);
    275   ASSERT (Source != NULL);
    276 
    277   while (*Source != '\0') {
    278     //
    279     // If any Unicode characters in Source contain
    280     // non-zero value in the upper 8 bits, then ASSERT().
    281     //
    282     ASSERT (*Source < 0x100);
    283     *(Destination++) = (CHAR8) *(Source++);
    284   }
    285 
    286   *Destination = '\0';
    287 
    288   return Destination;
    289 }
    290 
    291 /**
    292   Convert the decimal dotted IPv4 address into the binary IPv4 address.
    293 
    294   @param[in]   Str             The UNICODE string.
    295   @param[out]  Ip              The storage to return the ASCII string.
    296 
    297   @retval EFI_SUCCESS           The binary IP address is returned in Ip.
    298   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
    299 **/
    300 EFI_STATUS
    301 IScsiAsciiStrToIp (
    302   IN  CHAR8             *Str,
    303   OUT EFI_IPv4_ADDRESS  *Ip
    304   )
    305 {
    306   UINTN Index;
    307   UINTN Number;
    308 
    309   Index = 0;
    310 
    311   while (*Str != 0) {
    312 
    313     if (Index > 3) {
    314       return EFI_INVALID_PARAMETER;
    315     }
    316 
    317     Number = 0;
    318     while (NET_IS_DIGIT (*Str)) {
    319       Number = Number * 10 + (*Str - '0');
    320       Str++;
    321     }
    322 
    323     if (Number > 0xFF) {
    324       return EFI_INVALID_PARAMETER;
    325     }
    326 
    327     Ip->Addr[Index] = (UINT8) Number;
    328 
    329     if ((*Str != '\0') && (*Str != '.')) {
    330       //
    331       // The current character should be either the NULL terminator or
    332       // the dot delimiter.
    333       //
    334       return EFI_INVALID_PARAMETER;
    335     }
    336 
    337     if (*Str == '.') {
    338       //
    339       // Skip the delimiter.
    340       //
    341       Str++;
    342     }
    343 
    344     Index++;
    345   }
    346 
    347   if (Index != 4) {
    348     return EFI_INVALID_PARAMETER;
    349   }
    350 
    351   return EFI_SUCCESS;
    352 }
    353 
    354 /**
    355   Convert the mac address into a hexadecimal encoded "-" seperated string.
    356 
    357   @param[in]  Mac     The mac address.
    358   @param[in]  Len     Length in bytes of the mac address.
    359   @param[in]  VlanId  VLAN ID of the network device.
    360   @param[out] Str     The storage to return the mac string.
    361 **/
    362 VOID
    363 IScsiMacAddrToStr (
    364   IN  EFI_MAC_ADDRESS  *Mac,
    365   IN  UINT32           Len,
    366   IN  UINT16           VlanId,
    367   OUT CHAR16           *Str
    368   )
    369 {
    370   UINT32  Index;
    371   CHAR16  *String;
    372 
    373   for (Index = 0; Index < Len; Index++) {
    374     Str[3 * Index]      = (CHAR16) IScsiHexString[(Mac->Addr[Index] >> 4) & 0x0F];
    375     Str[3 * Index + 1]  = (CHAR16) IScsiHexString[Mac->Addr[Index] & 0x0F];
    376     Str[3 * Index + 2]  = L'-';
    377   }
    378 
    379   String = &Str[3 * Index - 1] ;
    380   if (VlanId != 0) {
    381     String += UnicodeSPrint (String, 6 * sizeof (CHAR16), L"\\%04x", (UINTN) VlanId);
    382   }
    383 
    384   *String = L'\0';
    385 }
    386 
    387 /**
    388   Convert the binary encoded buffer into a hexadecimal encoded string.
    389 
    390   @param[in]       BinBuffer   The buffer containing the binary data.
    391   @param[in]       BinLength   Length of the binary buffer.
    392   @param[in, out]  HexStr      Pointer to the string.
    393   @param[in, out]  HexLength   The length of the string.
    394 
    395   @retval EFI_SUCCESS          The binary data is converted to the hexadecimal string
    396                                and the length of the string is updated.
    397   @retval EFI_BUFFER_TOO_SMALL The string is too small.
    398   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
    399 **/
    400 EFI_STATUS
    401 IScsiBinToHex (
    402   IN     UINT8  *BinBuffer,
    403   IN     UINT32 BinLength,
    404   IN OUT CHAR8  *HexStr,
    405   IN OUT UINT32 *HexLength
    406   )
    407 {
    408   UINTN Index;
    409 
    410   if ((HexStr == NULL) || (BinBuffer == NULL) || (BinLength == 0)) {
    411     return EFI_INVALID_PARAMETER;
    412   }
    413 
    414   if (((*HexLength) - 3) < BinLength * 2) {
    415     *HexLength = BinLength * 2 + 3;
    416     return EFI_BUFFER_TOO_SMALL;
    417   }
    418 
    419   *HexLength = BinLength * 2 + 3;
    420   //
    421   // Prefix for Hex String
    422   //
    423   HexStr[0] = '0';
    424   HexStr[1] = 'x';
    425 
    426   for (Index = 0; Index < BinLength; Index++) {
    427     HexStr[Index * 2 + 2] = IScsiHexString[BinBuffer[Index] >> 4];
    428     HexStr[Index * 2 + 3] = IScsiHexString[BinBuffer[Index] & 0x0F];
    429   }
    430 
    431   HexStr[Index * 2 + 2] = '\0';
    432 
    433   return EFI_SUCCESS;
    434 }
    435 
    436 /**
    437   Convert the hexadecimal string into a binary encoded buffer.
    438 
    439   @param[in, out]  BinBuffer   The binary buffer.
    440   @param[in, out]  BinLength   Length of the binary buffer.
    441   @param[in]       HexStr      The hexadecimal string.
    442 
    443   @retval EFI_SUCCESS          The hexadecimal string is converted into a binary
    444                                encoded buffer.
    445   @retval EFI_BUFFER_TOO_SMALL The binary buffer is too small to hold the converted data.
    446 **/
    447 EFI_STATUS
    448 IScsiHexToBin (
    449   IN OUT UINT8  *BinBuffer,
    450   IN OUT UINT32 *BinLength,
    451   IN     CHAR8  *HexStr
    452   )
    453 {
    454   UINTN   Index;
    455   UINTN   Length;
    456   UINT8   Digit;
    457   CHAR8   TemStr[2];
    458 
    459   ZeroMem (TemStr, sizeof (TemStr));
    460 
    461   //
    462   // Find out how many hex characters the string has.
    463   //
    464   if ((HexStr[0] == '0') && ((HexStr[1] == 'x') || (HexStr[1] == 'X'))) {
    465     HexStr += 2;
    466   }
    467 
    468   Length = AsciiStrLen (HexStr);
    469 
    470   for (Index = 0; Index < Length; Index ++) {
    471     TemStr[0] = HexStr[Index];
    472     Digit = (UINT8) AsciiStrHexToUint64 (TemStr);
    473     if (Digit == 0 && TemStr[0] != '0') {
    474       //
    475       // Invalid Lun Char
    476       //
    477       break;
    478     }
    479     if ((Index & 1) == 0) {
    480       BinBuffer [Index/2] = Digit;
    481     } else {
    482       BinBuffer [Index/2] = (UINT8) ((BinBuffer [Index/2] << 4) + Digit);
    483     }
    484   }
    485 
    486   *BinLength = (UINT32) ((Index + 1)/2);
    487 
    488   return EFI_SUCCESS;
    489 }
    490 
    491 /**
    492   Generate random numbers.
    493 
    494   @param[in, out]  Rand       The buffer to contain random numbers.
    495   @param[in]       RandLength The length of the Rand buffer.
    496 **/
    497 VOID
    498 IScsiGenRandom (
    499   IN OUT UINT8  *Rand,
    500   IN     UINTN  RandLength
    501   )
    502 {
    503   UINT32  Random;
    504 
    505   while (RandLength > 0) {
    506     Random  = NET_RANDOM (NetRandomInitSeed ());
    507     *Rand++ = (UINT8) (Random);
    508     RandLength--;
    509   }
    510 }
    511 
    512 /**
    513   Create the iSCSI driver data..
    514 
    515   @param[in] Image      The handle of the driver image.
    516   @param[in] Controller The handle of the controller.
    517 
    518   @return The iSCSI driver data created.
    519   @retval NULL Other errors as indicated.
    520 **/
    521 ISCSI_DRIVER_DATA *
    522 IScsiCreateDriverData (
    523   IN EFI_HANDLE  Image,
    524   IN EFI_HANDLE  Controller
    525   )
    526 {
    527   ISCSI_DRIVER_DATA *Private;
    528   EFI_STATUS        Status;
    529 
    530   Private = AllocateZeroPool (sizeof (ISCSI_DRIVER_DATA));
    531   if (Private == NULL) {
    532     return NULL;
    533   }
    534 
    535   Private->Signature  = ISCSI_DRIVER_DATA_SIGNATURE;
    536   Private->Image      = Image;
    537   Private->Controller = Controller;
    538 
    539   //
    540   // Create an event to be signal when the BS to RT transition is triggerd so
    541   // as to abort the iSCSI session.
    542   //
    543   Status = gBS->CreateEventEx (
    544                   EVT_NOTIFY_SIGNAL,
    545                   TPL_CALLBACK,
    546                   IScsiOnExitBootService,
    547                   Private,
    548                   &gEfiEventExitBootServicesGuid,
    549                   &Private->ExitBootServiceEvent
    550                   );
    551   if (EFI_ERROR (Status)) {
    552     FreePool (Private);
    553     return NULL;
    554   }
    555 
    556   CopyMem(&Private->IScsiExtScsiPassThru, &gIScsiExtScsiPassThruProtocolTemplate, sizeof(EFI_EXT_SCSI_PASS_THRU_PROTOCOL));
    557 
    558   //
    559   // 0 is designated to the TargetId, so use another value for the AdapterId.
    560   //
    561   Private->ExtScsiPassThruMode.AdapterId = 2;
    562   Private->ExtScsiPassThruMode.Attributes = EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_PHYSICAL | EFI_EXT_SCSI_PASS_THRU_ATTRIBUTES_LOGICAL;
    563   Private->ExtScsiPassThruMode.IoAlign  = 4;
    564   Private->IScsiExtScsiPassThru.Mode    = &Private->ExtScsiPassThruMode;
    565 
    566   //
    567   // Install the Ext SCSI PASS THRU protocol.
    568   //
    569   Status = gBS->InstallProtocolInterface (
    570                   &Private->ExtScsiPassThruHandle,
    571                   &gEfiExtScsiPassThruProtocolGuid,
    572                   EFI_NATIVE_INTERFACE,
    573                   &Private->IScsiExtScsiPassThru
    574                   );
    575   if (EFI_ERROR (Status)) {
    576     gBS->CloseEvent (Private->ExitBootServiceEvent);
    577     FreePool (Private);
    578 
    579     return NULL;
    580   }
    581 
    582   IScsiSessionInit (&Private->Session, FALSE);
    583 
    584   return Private;
    585 }
    586 
    587 /**
    588   Clean the iSCSI driver data.
    589 
    590   @param[in]  Private The iSCSI driver data.
    591 **/
    592 VOID
    593 IScsiCleanDriverData (
    594   IN ISCSI_DRIVER_DATA  *Private
    595   )
    596 {
    597   if (Private->DevicePath != NULL) {
    598     gBS->UninstallProtocolInterface (
    599           Private->ExtScsiPassThruHandle,
    600           &gEfiDevicePathProtocolGuid,
    601           Private->DevicePath
    602           );
    603 
    604     FreePool (Private->DevicePath);
    605   }
    606 
    607   if (Private->ExtScsiPassThruHandle != NULL) {
    608     gBS->UninstallProtocolInterface (
    609           Private->ExtScsiPassThruHandle,
    610           &gEfiExtScsiPassThruProtocolGuid,
    611           &Private->IScsiExtScsiPassThru
    612           );
    613   }
    614 
    615   gBS->CloseEvent (Private->ExitBootServiceEvent);
    616 
    617   FreePool (Private);
    618 }
    619 
    620 /**
    621   Check wheather the Controller is configured to use DHCP protocol.
    622 
    623   @param[in]  Controller           The handle of the controller.
    624 
    625   @retval TRUE                     The handle of the controller need the Dhcp protocol.
    626   @retval FALSE                    The handle of the controller does not need the Dhcp protocol.
    627 
    628 **/
    629 BOOLEAN
    630 IScsiDhcpIsConfigured (
    631   IN EFI_HANDLE  Controller
    632   )
    633 {
    634   EFI_STATUS                  Status;
    635   EFI_MAC_ADDRESS             MacAddress;
    636   UINTN                       HwAddressSize;
    637   UINT16                      VlanId;
    638   CHAR16                      MacString[70];
    639   ISCSI_SESSION_CONFIG_NVDATA *ConfigDataTmp;
    640 
    641   //
    642   // Get the mac string, it's the name of various variable
    643   //
    644   Status = NetLibGetMacAddress (Controller, &MacAddress, &HwAddressSize);
    645   if (EFI_ERROR (Status)) {
    646     return FALSE;
    647   }
    648   VlanId = NetLibGetVlanId (Controller);
    649   IScsiMacAddrToStr (&MacAddress, (UINT32) HwAddressSize, VlanId, MacString);
    650 
    651   //
    652   // Get the normal configuration.
    653   //
    654   Status = GetVariable2 (
    655              MacString,
    656              &gEfiIScsiInitiatorNameProtocolGuid,
    657              (VOID**)&ConfigDataTmp,
    658              NULL
    659              );
    660   if (ConfigDataTmp == NULL || EFI_ERROR (Status)) {
    661     return FALSE;
    662   }
    663 
    664   if (ConfigDataTmp->Enabled && ConfigDataTmp->InitiatorInfoFromDhcp) {
    665     FreePool (ConfigDataTmp);
    666     return TRUE;
    667   }
    668 
    669   FreePool (ConfigDataTmp);
    670   return FALSE;
    671 }
    672 
    673 /**
    674   Get the various configuration data of this iSCSI instance.
    675 
    676   @param[in]  Private   The iSCSI driver data.
    677 
    678   @retval EFI_SUCCESS   The configuration of this instance is got.
    679   @retval EFI_ABORTED   The operation was aborted.
    680   @retval Others        Other errors as indicated.
    681 **/
    682 EFI_STATUS
    683 IScsiGetConfigData (
    684   IN ISCSI_DRIVER_DATA  *Private
    685   )
    686 {
    687   EFI_STATUS                  Status;
    688   ISCSI_SESSION               *Session;
    689   UINTN                       BufferSize;
    690   EFI_MAC_ADDRESS             MacAddress;
    691   UINTN                       HwAddressSize;
    692   UINT16                      VlanId;
    693   CHAR16                      MacString[70];
    694 
    695   //
    696   // get the iSCSI Initiator Name
    697   //
    698   Session                       = &Private->Session;
    699   Session->InitiatorNameLength  = ISCSI_NAME_MAX_SIZE;
    700   Status = gIScsiInitiatorName.Get (
    701                                 &gIScsiInitiatorName,
    702                                 &Session->InitiatorNameLength,
    703                                 Session->InitiatorName
    704                                 );
    705   if (EFI_ERROR (Status)) {
    706     return Status;
    707   }
    708 
    709   //
    710   // Get the mac string, it's the name of various variable
    711   //
    712   Status = NetLibGetMacAddress (Private->Controller, &MacAddress, &HwAddressSize);
    713   ASSERT (Status == EFI_SUCCESS);
    714   VlanId = NetLibGetVlanId (Private->Controller);
    715   IScsiMacAddrToStr (&MacAddress, (UINT32) HwAddressSize, VlanId, MacString);
    716 
    717   //
    718   // Get the normal configuration.
    719   //
    720   BufferSize = sizeof (Session->ConfigData.NvData);
    721   Status = gRT->GetVariable (
    722                   MacString,
    723                   &gEfiIScsiInitiatorNameProtocolGuid,
    724                   NULL,
    725                   &BufferSize,
    726                   &Session->ConfigData.NvData
    727                   );
    728   if (EFI_ERROR (Status)) {
    729     return Status;
    730   }
    731 
    732   if (!Session->ConfigData.NvData.Enabled) {
    733     return EFI_ABORTED;
    734   }
    735   //
    736   // Get the CHAP Auth information.
    737   //
    738   BufferSize = sizeof (Session->AuthData.AuthConfig);
    739   Status = gRT->GetVariable (
    740                   MacString,
    741                   &gIScsiCHAPAuthInfoGuid,
    742                   NULL,
    743                   &BufferSize,
    744                   &Session->AuthData.AuthConfig
    745                   );
    746 
    747   if (!EFI_ERROR (Status) && Session->ConfigData.NvData.InitiatorInfoFromDhcp) {
    748     //
    749     // Start dhcp.
    750     //
    751     Status = IScsiDoDhcp (Private->Image, Private->Controller, &Session->ConfigData);
    752   }
    753 
    754   return Status;
    755 }
    756 
    757 /**
    758   Get the device path of the iSCSI tcp connection and update it.
    759 
    760   @param[in]  Private The iSCSI driver data.
    761 
    762   @return The updated device path.
    763   @retval NULL Other errors as indicated.
    764 **/
    765 EFI_DEVICE_PATH_PROTOCOL *
    766 IScsiGetTcpConnDevicePath (
    767   IN ISCSI_DRIVER_DATA  *Private
    768   )
    769 {
    770   ISCSI_SESSION             *Session;
    771   ISCSI_CONNECTION          *Conn;
    772   TCP4_IO                   *Tcp4Io;
    773   EFI_DEVICE_PATH_PROTOCOL  *DevicePath;
    774   EFI_STATUS                Status;
    775   EFI_DEV_PATH              *DPathNode;
    776 
    777   Session = &Private->Session;
    778   if (Session->State != SESSION_STATE_LOGGED_IN) {
    779     return NULL;
    780   }
    781 
    782   Conn = NET_LIST_USER_STRUCT_S (
    783           Session->Conns.ForwardLink,
    784           ISCSI_CONNECTION,
    785           Link,
    786           ISCSI_CONNECTION_SIGNATURE
    787           );
    788   Tcp4Io = &Conn->Tcp4Io;
    789 
    790   Status = gBS->HandleProtocol (
    791                   Tcp4Io->Handle,
    792                   &gEfiDevicePathProtocolGuid,
    793                   (VOID **)&DevicePath
    794                   );
    795   if (EFI_ERROR (Status)) {
    796     return NULL;
    797   }
    798   //
    799   // Duplicate it.
    800   //
    801   DevicePath  = DuplicateDevicePath (DevicePath);
    802   if (DevicePath == NULL) {
    803     return NULL;
    804   }
    805 
    806   DPathNode   = (EFI_DEV_PATH *) DevicePath;
    807 
    808   while (!IsDevicePathEnd (&DPathNode->DevPath)) {
    809     if ((DevicePathType (&DPathNode->DevPath) == MESSAGING_DEVICE_PATH) &&
    810         (DevicePathSubType (&DPathNode->DevPath) == MSG_IPv4_DP)
    811         ) {
    812 
    813       DPathNode->Ipv4.LocalPort       = 0;
    814       DPathNode->Ipv4.StaticIpAddress =
    815         (BOOLEAN) (!Session->ConfigData.NvData.InitiatorInfoFromDhcp);
    816 
    817       //
    818       //  Add a judgement here to support previous versions of IPv4_DEVICE_PATH.
    819       //  In previous versions of IPv4_DEVICE_PATH, GatewayIpAddress and SubnetMask
    820       //  do not exist.
    821       //  In new version of IPv4_DEVICE_PATH, structcure length is 27.
    822       //
    823       if (DevicePathNodeLength (&DPathNode->Ipv4) == IP4_NODE_LEN_NEW_VERSIONS) {
    824 
    825         IP4_COPY_ADDRESS (
    826           &DPathNode->Ipv4.GatewayIpAddress,
    827           &Session->ConfigData.NvData.Gateway
    828           );
    829 
    830         IP4_COPY_ADDRESS (
    831           &DPathNode->Ipv4.SubnetMask,
    832           &Session->ConfigData.NvData.SubnetMask
    833           );
    834       }
    835 
    836       break;
    837     }
    838 
    839     DPathNode = (EFI_DEV_PATH *) NextDevicePathNode (&DPathNode->DevPath);
    840   }
    841 
    842   return DevicePath;
    843 }
    844 
    845 /**
    846   Abort the session when the transition from BS to RT is initiated.
    847 
    848   @param[in]   Event  The event signaled.
    849   @param[in]  Context The iSCSI driver data.
    850 **/
    851 VOID
    852 EFIAPI
    853 IScsiOnExitBootService (
    854   IN EFI_EVENT  Event,
    855   IN VOID       *Context
    856   )
    857 {
    858   ISCSI_DRIVER_DATA *Private;
    859 
    860   Private = (ISCSI_DRIVER_DATA *) Context;
    861   gBS->CloseEvent (Private->ExitBootServiceEvent);
    862 
    863   IScsiSessionAbort (&Private->Session);
    864 }
    865 
    866 /**
    867   Tests whether a controller handle is being managed by IScsi driver.
    868 
    869   This function tests whether the driver specified by DriverBindingHandle is
    870   currently managing the controller specified by ControllerHandle.  This test
    871   is performed by evaluating if the the protocol specified by ProtocolGuid is
    872   present on ControllerHandle and is was opened by DriverBindingHandle and Nic
    873   Device handle with an attribute of EFI_OPEN_PROTOCOL_BY_DRIVER.
    874   If ProtocolGuid is NULL, then ASSERT().
    875 
    876   @param  ControllerHandle     A handle for a controller to test.
    877   @param  DriverBindingHandle  Specifies the driver binding handle for the
    878                                driver.
    879   @param  ProtocolGuid         Specifies the protocol that the driver specified
    880                                by DriverBindingHandle opens in its Start()
    881                                function.
    882 
    883   @retval EFI_SUCCESS          ControllerHandle is managed by the driver
    884                                specified by DriverBindingHandle.
    885   @retval EFI_UNSUPPORTED      ControllerHandle is not managed by the driver
    886                                specified by DriverBindingHandle.
    887 
    888 **/
    889 EFI_STATUS
    890 EFIAPI
    891 IScsiTestManagedDevice (
    892   IN  EFI_HANDLE       ControllerHandle,
    893   IN  EFI_HANDLE       DriverBindingHandle,
    894   IN  EFI_GUID         *ProtocolGuid
    895   )
    896 {
    897   EFI_STATUS     Status;
    898   VOID           *ManagedInterface;
    899   EFI_HANDLE     NicControllerHandle;
    900 
    901   ASSERT (ProtocolGuid != NULL);
    902 
    903   NicControllerHandle = NetLibGetNicHandle (ControllerHandle, ProtocolGuid);
    904   if (NicControllerHandle == NULL) {
    905     return EFI_UNSUPPORTED;
    906   }
    907 
    908   Status = gBS->OpenProtocol (
    909                   ControllerHandle,
    910                   (EFI_GUID *) ProtocolGuid,
    911                   &ManagedInterface,
    912                   DriverBindingHandle,
    913                   NicControllerHandle,
    914                   EFI_OPEN_PROTOCOL_BY_DRIVER
    915                   );
    916   if (!EFI_ERROR (Status)) {
    917     gBS->CloseProtocol (
    918            ControllerHandle,
    919            (EFI_GUID *) ProtocolGuid,
    920            DriverBindingHandle,
    921            NicControllerHandle
    922            );
    923     return EFI_UNSUPPORTED;
    924   }
    925 
    926   if (Status != EFI_ALREADY_STARTED) {
    927     return EFI_UNSUPPORTED;
    928   }
    929 
    930   return EFI_SUCCESS;
    931 }
    932