Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2   Helper functions for configuring or getting the parameters relating to Ip4.
      3 
      4 Copyright (c) 2015 - 2016, 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 "Ip4Impl.h"
     16 
     17 CHAR16    mIp4Config2StorageName[]     = L"IP4_CONFIG2_IFR_NVDATA";
     18 
     19 /**
     20   Calculate the prefix length of the IPv4 subnet mask.
     21 
     22   @param[in]  SubnetMask The IPv4 subnet mask.
     23 
     24   @return The prefix length of the subnet mask.
     25   @retval 0 Other errors as indicated.
     26 
     27 **/
     28 UINT8
     29 GetSubnetMaskPrefixLength (
     30   IN EFI_IPv4_ADDRESS  *SubnetMask
     31   )
     32 {
     33   UINT8   Len;
     34   UINT32  ReverseMask;
     35 
     36   //
     37   // The SubnetMask is in network byte order.
     38   //
     39   ReverseMask = SwapBytes32 (*(UINT32 *)&SubnetMask[0]);
     40 
     41   //
     42   // Reverse it.
     43   //
     44   ReverseMask = ~ReverseMask;
     45 
     46   if ((ReverseMask & (ReverseMask + 1)) != 0) {
     47     return 0;
     48   }
     49 
     50   Len = 0;
     51 
     52   while (ReverseMask != 0) {
     53     ReverseMask = ReverseMask >> 1;
     54     Len++;
     55   }
     56 
     57   return (UINT8) (32 - Len);
     58 }
     59 
     60 /**
     61   Convert the decimal dotted IPv4 address into the binary IPv4 address.
     62 
     63   @param[in]   Str             The UNICODE string.
     64   @param[out]  Ip              The storage to return the IPv4 address.
     65 
     66   @retval EFI_SUCCESS           The binary IP address is returned in Ip.
     67   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
     68 
     69 **/
     70 EFI_STATUS
     71 Ip4Config2StrToIp (
     72   IN  CHAR16            *Str,
     73   OUT EFI_IPv4_ADDRESS  *Ip
     74   )
     75 {
     76   UINTN Index;
     77   UINTN Number;
     78 
     79   Index = 0;
     80 
     81   while (*Str != L'\0') {
     82 
     83     if (Index > 3) {
     84       return EFI_INVALID_PARAMETER;
     85     }
     86 
     87     Number = 0;
     88     while ((*Str >= L'0') && (*Str <= L'9')) {
     89       Number = Number * 10 + (*Str - L'0');
     90       Str++;
     91     }
     92 
     93     if (Number > 0xFF) {
     94       return EFI_INVALID_PARAMETER;
     95     }
     96 
     97     Ip->Addr[Index] = (UINT8) Number;
     98 
     99     if ((*Str != L'\0') && (*Str != L'.')) {
    100       //
    101       // The current character should be either the NULL terminator or
    102       // the dot delimiter.
    103       //
    104       return EFI_INVALID_PARAMETER;
    105     }
    106 
    107     if (*Str == L'.') {
    108       //
    109       // Skip the delimiter.
    110       //
    111       Str++;
    112     }
    113 
    114     Index++;
    115   }
    116 
    117   if (Index != 4) {
    118     return EFI_INVALID_PARAMETER;
    119   }
    120 
    121   return EFI_SUCCESS;
    122 }
    123 
    124 /**
    125   Convert the decimal dotted IPv4 addresses separated by space into the binary IPv4 address list.
    126 
    127   @param[in]   Str             The UNICODE string contains IPv4 addresses.
    128   @param[out]  PtrIpList       The storage to return the IPv4 address list.
    129   @param[out]  IpCount         The size of the IPv4 address list.
    130 
    131   @retval EFI_SUCCESS           The binary IP address list is returned in PtrIpList.
    132   @retval EFI_OUT_OF_RESOURCES  Error occurs in allocating memory.
    133   @retval EFI_INVALID_PARAMETER The IP string is malformatted.
    134 
    135 **/
    136 EFI_STATUS
    137 Ip4Config2StrToIpList (
    138   IN  CHAR16            *Str,
    139   OUT EFI_IPv4_ADDRESS  **PtrIpList,
    140   OUT UINTN             *IpCount
    141   )
    142 {
    143   UINTN              BeginIndex;
    144   UINTN              EndIndex;
    145   UINTN              Index;
    146   UINTN              IpIndex;
    147   CHAR16             *StrTemp;
    148   BOOLEAN            SpaceTag;
    149 
    150   BeginIndex = 0;
    151   EndIndex   = BeginIndex;
    152   Index      = 0;
    153   IpIndex    = 0;
    154   StrTemp    = NULL;
    155   SpaceTag   = TRUE;
    156 
    157   *PtrIpList = NULL;
    158   *IpCount   = 0;
    159 
    160   if (Str == NULL) {
    161     return EFI_SUCCESS;
    162   }
    163 
    164   //
    165   // Get the number of Ip.
    166   //
    167   while (*(Str + Index) != L'\0') {
    168     if (*(Str + Index) == L' ') {
    169       SpaceTag = TRUE;
    170     } else {
    171       if (SpaceTag) {
    172         (*IpCount)++;
    173         SpaceTag = FALSE;
    174       }
    175     }
    176 
    177     Index++;
    178   }
    179 
    180   if (*IpCount == 0) {
    181     return EFI_SUCCESS;
    182   }
    183 
    184   //
    185   // Allocate buffer for IpList.
    186   //
    187   *PtrIpList = AllocateZeroPool(*IpCount * sizeof(EFI_IPv4_ADDRESS));
    188   if (*PtrIpList == NULL) {
    189     return EFI_OUT_OF_RESOURCES;
    190   }
    191 
    192   //
    193   // Get IpList from Str.
    194   //
    195   Index = 0;
    196   while (*(Str + Index) != L'\0') {
    197     if (*(Str + Index) == L' ') {
    198       if(!SpaceTag) {
    199         StrTemp = AllocateZeroPool((EndIndex - BeginIndex + 1) * sizeof(CHAR16));
    200         if (StrTemp == NULL) {
    201           FreePool(*PtrIpList);
    202           *PtrIpList = NULL;
    203           *IpCount = 0;
    204           return EFI_OUT_OF_RESOURCES;
    205         }
    206 
    207         CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof(CHAR16));
    208         *(StrTemp + (EndIndex - BeginIndex)) = L'\0';
    209 
    210         if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
    211           FreePool(StrTemp);
    212           FreePool(*PtrIpList);
    213           *PtrIpList = NULL;
    214           *IpCount = 0;
    215           return EFI_INVALID_PARAMETER;
    216         }
    217 
    218         BeginIndex = EndIndex;
    219         IpIndex++;
    220 
    221         FreePool(StrTemp);
    222       }
    223 
    224       BeginIndex++;
    225       EndIndex++;
    226       SpaceTag = TRUE;
    227     } else {
    228       EndIndex++;
    229       SpaceTag = FALSE;
    230     }
    231 
    232     Index++;
    233 
    234     if (*(Str + Index) == L'\0') {
    235       if (!SpaceTag) {
    236         StrTemp = AllocateZeroPool((EndIndex - BeginIndex + 1) * sizeof(CHAR16));
    237         if (StrTemp == NULL) {
    238           FreePool(*PtrIpList);
    239           *PtrIpList = NULL;
    240           *IpCount = 0;
    241           return EFI_OUT_OF_RESOURCES;
    242         }
    243 
    244         CopyMem (StrTemp, Str + BeginIndex, (EndIndex - BeginIndex) * sizeof(CHAR16));
    245         *(StrTemp + (EndIndex - BeginIndex)) = L'\0';
    246 
    247         if (Ip4Config2StrToIp (StrTemp, &((*PtrIpList)[IpIndex])) != EFI_SUCCESS) {
    248           FreePool(StrTemp);
    249           FreePool(*PtrIpList);
    250           *PtrIpList = NULL;
    251           *IpCount = 0;
    252           return EFI_INVALID_PARAMETER;
    253         }
    254 
    255         FreePool(StrTemp);
    256       }
    257     }
    258   }
    259 
    260   return EFI_SUCCESS;
    261 }
    262 
    263 /**
    264   Convert the IPv4 address into a dotted string.
    265 
    266   @param[in]   Ip   The IPv4 address.
    267   @param[out]  Str  The dotted IP string.
    268 
    269 **/
    270 VOID
    271 Ip4Config2IpToStr (
    272   IN  EFI_IPv4_ADDRESS  *Ip,
    273   OUT CHAR16            *Str
    274   )
    275 {
    276   UnicodeSPrint (
    277     Str,
    278     2 * IP4_STR_MAX_SIZE,
    279     L"%d.%d.%d.%d",
    280     Ip->Addr[0],
    281     Ip->Addr[1],
    282     Ip->Addr[2],
    283     Ip->Addr[3]
    284     );
    285 }
    286 
    287 
    288 /**
    289   Convert the IPv4 address list into string consists of several decimal
    290   dotted IPv4 addresses separated by space.
    291 
    292   @param[in]   Ip        The IPv4 address list.
    293   @param[in]   IpCount   The size of IPv4 address list.
    294   @param[out]  Str       The string contains several decimal dotted
    295                          IPv4 addresses separated by space.
    296 **/
    297 VOID
    298 Ip4Config2IpListToStr (
    299   IN  EFI_IPv4_ADDRESS  *Ip,
    300   IN  UINTN             IpCount,
    301   OUT CHAR16            *Str
    302   )
    303 {
    304   UINTN            Index;
    305   UINTN            TemIndex;
    306   UINTN            StrIndex;
    307   CHAR16           *TempStr;
    308   EFI_IPv4_ADDRESS *TempIp;
    309 
    310   Index    = 0;
    311   TemIndex = 0;
    312   StrIndex = 0;
    313   TempStr  = NULL;
    314   TempIp   = NULL;
    315 
    316   for (Index = 0; Index < IpCount; Index ++) {
    317     TempIp = Ip + Index;
    318     if (TempStr == NULL) {
    319       TempStr = AllocateZeroPool(2 * IP4_STR_MAX_SIZE);
    320       ASSERT(TempStr != NULL);
    321     }
    322 
    323     UnicodeSPrint (
    324       TempStr,
    325       2 * IP4_STR_MAX_SIZE,
    326       L"%d.%d.%d.%d",
    327       TempIp->Addr[0],
    328       TempIp->Addr[1],
    329       TempIp->Addr[2],
    330       TempIp->Addr[3]
    331       );
    332 
    333     for (TemIndex = 0; TemIndex < IP4_STR_MAX_SIZE; TemIndex ++) {
    334       if (*(TempStr + TemIndex) == L'\0') {
    335         if (Index == IpCount - 1) {
    336           Str[StrIndex++] = L'\0';
    337         } else {
    338           Str[StrIndex++] = L' ';
    339         }
    340         break;
    341       } else {
    342         Str[StrIndex++] = *(TempStr + TemIndex);
    343       }
    344     }
    345   }
    346 
    347   if (TempStr != NULL) {
    348     FreePool(TempStr);
    349   }
    350 }
    351 
    352 /**
    353   The notify function of create event when performing a manual configuration.
    354 
    355   @param[in]    Event        The pointer of Event.
    356   @param[in]    Context      The pointer of Context.
    357 
    358 **/
    359 VOID
    360 EFIAPI
    361 Ip4Config2ManualAddressNotify (
    362   IN EFI_EVENT    Event,
    363   IN VOID         *Context
    364   )
    365 {
    366   *((BOOLEAN *) Context) = TRUE;
    367 }
    368 
    369 /**
    370   Convert the network configuration data into the IFR data.
    371 
    372   @param[in]       Instance          The IP4 config2 instance.
    373   @param[in, out]  IfrNvData         The IFR nv data.
    374 
    375   @retval EFI_SUCCESS            The configure parameter to IFR data was
    376                                  set successfully.
    377   @retval EFI_INVALID_PARAMETER  Source instance or target IFR data is not available.
    378   @retval Others                 Other errors as indicated.
    379 
    380 **/
    381 EFI_STATUS
    382 Ip4Config2ConvertConfigNvDataToIfrNvData (
    383   IN     IP4_CONFIG2_INSTANCE       *Instance,
    384   IN OUT IP4_CONFIG2_IFR_NVDATA     *IfrNvData
    385   )
    386 {
    387   IP4_SERVICE                                *IpSb;
    388   EFI_IP4_CONFIG2_PROTOCOL                   *Ip4Config2;
    389   EFI_IP4_CONFIG2_INTERFACE_INFO             *Ip4Info;
    390   EFI_IP4_CONFIG2_POLICY                     Policy;
    391   UINTN                                      DataSize;
    392   UINTN                                      GatewaySize;
    393   EFI_IPv4_ADDRESS                           GatewayAddress;
    394   EFI_STATUS                                 Status;
    395   UINTN                                      DnsSize;
    396   UINTN                                      DnsCount;
    397   EFI_IPv4_ADDRESS                           *DnsAddress;
    398 
    399   Status      = EFI_SUCCESS;
    400   Ip4Config2  = &Instance->Ip4Config2;
    401   Ip4Info     = NULL;
    402   DnsAddress  = NULL;
    403   GatewaySize = sizeof (EFI_IPv4_ADDRESS);
    404 
    405   if ((IfrNvData == NULL) || (Instance == NULL)) {
    406     return EFI_INVALID_PARAMETER;
    407   }
    408 
    409   NET_CHECK_SIGNATURE (Instance, IP4_CONFIG2_INSTANCE_SIGNATURE);
    410 
    411   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
    412 
    413   if (IpSb->DefaultInterface->Configured) {
    414     IfrNvData->Configure = 1;
    415   } else {
    416     IfrNvData->Configure = 0;
    417     goto Exit;
    418   }
    419 
    420   //
    421   // Get the Policy info.
    422   //
    423   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
    424   Status   = Ip4Config2->GetData (
    425                            Ip4Config2,
    426                            Ip4Config2DataTypePolicy,
    427                            &DataSize,
    428                            &Policy
    429                            );
    430   if (EFI_ERROR (Status)) {
    431     goto Exit;
    432   }
    433 
    434   if (Policy == Ip4Config2PolicyStatic) {
    435     IfrNvData->DhcpEnable = FALSE;
    436   } else if (Policy == Ip4Config2PolicyDhcp) {
    437     IfrNvData->DhcpEnable = TRUE;
    438     goto Exit;
    439   }
    440 
    441   //
    442   // Get the interface info.
    443   //
    444   DataSize    = 0;
    445   Status = Ip4Config2->GetData (
    446                          Ip4Config2,
    447                          Ip4Config2DataTypeInterfaceInfo,
    448                          &DataSize,
    449                          NULL
    450                          );
    451   if (Status != EFI_BUFFER_TOO_SMALL) {
    452     return Status;
    453   }
    454 
    455   Ip4Info = AllocateZeroPool (DataSize);
    456   if (Ip4Info == NULL) {
    457     Status = EFI_OUT_OF_RESOURCES;
    458     return Status;
    459   }
    460 
    461   Status = Ip4Config2->GetData (
    462                          Ip4Config2,
    463                          Ip4Config2DataTypeInterfaceInfo,
    464                          &DataSize,
    465                          Ip4Info
    466                          );
    467   if (EFI_ERROR (Status)) {
    468     goto Exit;
    469   }
    470 
    471   //
    472   // Get the Gateway info.
    473   //
    474   Status = Ip4Config2->GetData (
    475                          Ip4Config2,
    476                          Ip4Config2DataTypeGateway,
    477                          &GatewaySize,
    478                          &GatewayAddress
    479                          );
    480   if (EFI_ERROR (Status)) {
    481     goto Exit;
    482   }
    483 
    484   //
    485   // Get the Dns info.
    486   //
    487   DnsSize = 0;
    488   Status = Ip4Config2->GetData (
    489                          Ip4Config2,
    490                          Ip4Config2DataTypeDnsServer,
    491                          &DnsSize,
    492                          NULL
    493                          );
    494   if ((Status != EFI_BUFFER_TOO_SMALL) && (Status != EFI_NOT_FOUND)) {
    495     goto Exit;
    496   }
    497 
    498   DnsCount = (UINT32) (DnsSize / sizeof (EFI_IPv4_ADDRESS));
    499 
    500   if (DnsSize > 0) {
    501     DnsAddress = AllocateZeroPool(DnsSize);
    502     if (DnsAddress == NULL) {
    503       Status = EFI_OUT_OF_RESOURCES;
    504       goto Exit;
    505     }
    506 
    507     Status = Ip4Config2->GetData (
    508                            Ip4Config2,
    509                            Ip4Config2DataTypeDnsServer,
    510                            &DnsSize,
    511                            DnsAddress
    512                            );
    513     if (EFI_ERROR (Status)) {
    514       goto Exit;
    515     }
    516   }
    517 
    518   Ip4Config2IpToStr (&Ip4Info->StationAddress, IfrNvData->StationAddress);
    519   Ip4Config2IpToStr (&Ip4Info->SubnetMask, IfrNvData->SubnetMask);
    520   Ip4Config2IpToStr (&GatewayAddress, IfrNvData->GatewayAddress);
    521   Ip4Config2IpListToStr (DnsAddress, DnsCount, IfrNvData->DnsAddress);
    522 
    523 Exit:
    524 
    525   if (DnsAddress != NULL) {
    526     FreePool(DnsAddress);
    527   }
    528 
    529   if (Ip4Info != NULL) {
    530     FreePool(Ip4Info);
    531   }
    532 
    533   return Status;
    534 }
    535 
    536 /**
    537   Convert the IFR data into the network configuration data and set the IP
    538   configure parameters for the NIC.
    539 
    540   @param[in]       IfrFormNvData     The IFR NV data.
    541   @param[in, out]  Instance          The IP4 config2 instance.
    542 
    543   @retval EFI_SUCCESS            The configure parameter for this NIC was
    544                                  set successfully.
    545   @retval EFI_INVALID_PARAMETER  The address information for setting is invalid.
    546   @retval Others                 Other errors as indicated.
    547 
    548 **/
    549 EFI_STATUS
    550 Ip4Config2ConvertIfrNvDataToConfigNvData (
    551   IN     IP4_CONFIG2_IFR_NVDATA     *IfrFormNvData,
    552   IN OUT IP4_CONFIG2_INSTANCE       *Instance
    553   )
    554 {
    555   EFI_STATUS                       Status;
    556   EFI_IP4_CONFIG2_PROTOCOL         *Ip4Cfg2;
    557   IP4_CONFIG2_NVDATA               *Ip4NvData;
    558 
    559   EFI_IP_ADDRESS                   StationAddress;
    560   EFI_IP_ADDRESS                   SubnetMask;
    561   EFI_IP_ADDRESS                   Gateway;
    562   IP4_ADDR                         Ip;
    563   EFI_IPv4_ADDRESS                 *DnsAddress;
    564   UINTN                            DnsCount;
    565   UINTN                            Index;
    566 
    567   EFI_EVENT                        TimeoutEvent;
    568   EFI_EVENT                        SetAddressEvent;
    569   BOOLEAN                          IsAddressOk;
    570   UINTN                            DataSize;
    571   EFI_INPUT_KEY                    Key;
    572 
    573   Status          = EFI_SUCCESS;
    574   Ip4Cfg2         = &Instance->Ip4Config2;
    575   Ip4NvData       = &Instance->Ip4NvData;
    576 
    577   DnsCount        = 0;
    578   DnsAddress      = NULL;
    579 
    580   TimeoutEvent    = NULL;
    581   SetAddressEvent = NULL;
    582 
    583 
    584 
    585   if (Instance == NULL || IfrFormNvData == NULL) {
    586     return EFI_INVALID_PARAMETER;
    587   }
    588 
    589   if (IfrFormNvData->Configure != TRUE) {
    590     return EFI_SUCCESS;
    591   }
    592 
    593   if (IfrFormNvData->DhcpEnable == TRUE) {
    594     Ip4NvData->Policy = Ip4Config2PolicyDhcp;
    595 
    596     Status = Ip4Cfg2->SetData (
    597                         Ip4Cfg2,
    598                         Ip4Config2DataTypePolicy,
    599                         sizeof (EFI_IP4_CONFIG2_POLICY),
    600                         &Ip4NvData->Policy
    601                         );
    602     if (EFI_ERROR(Status)) {
    603       return Status;
    604     }
    605   } else {
    606     //
    607     // Get Ip4NvData from IfrFormNvData if it is valid.
    608     //
    609     Ip4NvData->Policy = Ip4Config2PolicyStatic;
    610 
    611     Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
    612     if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
    613       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
    614       return EFI_INVALID_PARAMETER;
    615     }
    616 
    617     Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
    618     if (EFI_ERROR (Status) || !NetIp4IsUnicast (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) {
    619       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
    620       return EFI_INVALID_PARAMETER;
    621     }
    622 
    623     Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
    624     if (EFI_ERROR (Status) || ((Gateway.Addr[0] != 0) && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (SubnetMask.Addr[0])))) {
    625       CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
    626       return EFI_INVALID_PARAMETER;
    627     }
    628 
    629     Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
    630     if (!EFI_ERROR (Status) && DnsCount > 0) {
    631       for (Index = 0; Index < DnsCount; Index ++) {
    632         CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
    633         if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
    634           CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
    635           FreePool(DnsAddress);
    636           return EFI_INVALID_PARAMETER;
    637         }
    638       }
    639     } else {
    640       if (EFI_ERROR (Status)) {
    641         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
    642       }
    643     }
    644 
    645     if (Ip4NvData->ManualAddress != NULL) {
    646       FreePool(Ip4NvData->ManualAddress);
    647     }
    648     Ip4NvData->ManualAddressCount = 1;
    649     Ip4NvData->ManualAddress = AllocateZeroPool(sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS));
    650     if (Ip4NvData->ManualAddress == NULL) {
    651       if (DnsAddress != NULL) {
    652         FreePool(DnsAddress);
    653       }
    654 
    655       return EFI_OUT_OF_RESOURCES;
    656     }
    657     CopyMem(&Ip4NvData->ManualAddress->Address, &StationAddress.v4, sizeof(EFI_IPv4_ADDRESS));
    658     CopyMem(&Ip4NvData->ManualAddress->SubnetMask, &SubnetMask.v4, sizeof(EFI_IPv4_ADDRESS));
    659 
    660     if (Ip4NvData->GatewayAddress != NULL) {
    661       FreePool(Ip4NvData->GatewayAddress);
    662     }
    663     Ip4NvData->GatewayAddressCount = 1;
    664     Ip4NvData->GatewayAddress = AllocateZeroPool(sizeof(EFI_IPv4_ADDRESS));
    665     if (Ip4NvData->GatewayAddress == NULL) {
    666       if (DnsAddress != NULL) {
    667         FreePool(DnsAddress);
    668       }
    669       return EFI_OUT_OF_RESOURCES;
    670     }
    671     CopyMem(Ip4NvData->GatewayAddress, &Gateway.v4, sizeof(EFI_IPv4_ADDRESS));
    672 
    673     if (Ip4NvData->DnsAddress != NULL) {
    674       FreePool(Ip4NvData->DnsAddress);
    675     }
    676     Ip4NvData->DnsAddressCount = (UINT32) DnsCount;
    677     Ip4NvData->DnsAddress      = DnsAddress;
    678 
    679     //
    680     // Setting Ip4NvData.
    681     //
    682     Status = Ip4Cfg2->SetData (
    683                         Ip4Cfg2,
    684                         Ip4Config2DataTypePolicy,
    685                         sizeof (EFI_IP4_CONFIG2_POLICY),
    686                         &Ip4NvData->Policy
    687                         );
    688     if (EFI_ERROR(Status)) {
    689       return Status;
    690     }
    691 
    692     //
    693     // Create events & timers for asynchronous settings.
    694     //
    695     Status = gBS->CreateEvent (
    696                     EVT_TIMER,
    697                     TPL_CALLBACK,
    698                     NULL,
    699                     NULL,
    700                     &TimeoutEvent
    701                     );
    702     if (EFI_ERROR (Status)) {
    703       return EFI_OUT_OF_RESOURCES;
    704     }
    705 
    706     Status = gBS->CreateEvent (
    707                     EVT_NOTIFY_SIGNAL,
    708                     TPL_NOTIFY,
    709                     Ip4Config2ManualAddressNotify,
    710                     &IsAddressOk,
    711                     &SetAddressEvent
    712                     );
    713     if (EFI_ERROR (Status)) {
    714       goto Exit;
    715     }
    716 
    717     IsAddressOk = FALSE;
    718 
    719     Status = Ip4Cfg2->RegisterDataNotify (
    720                         Ip4Cfg2,
    721                         Ip4Config2DataTypeManualAddress,
    722                         SetAddressEvent
    723                         );
    724     if (EFI_ERROR (Status)) {
    725       goto Exit;
    726     }
    727 
    728     //
    729     // Set ManualAddress.
    730     //
    731     DataSize = Ip4NvData->ManualAddressCount * sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS);
    732     Status = Ip4Cfg2->SetData (
    733                         Ip4Cfg2,
    734                         Ip4Config2DataTypeManualAddress,
    735                         DataSize,
    736                         (VOID *) Ip4NvData->ManualAddress
    737                         );
    738 
    739     if (Status == EFI_NOT_READY) {
    740       gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);
    741       while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
    742         if (IsAddressOk) {
    743           Status = EFI_SUCCESS;
    744           break;
    745         }
    746       }
    747     }
    748 
    749     Ip4Cfg2->UnregisterDataNotify (
    750                Ip4Cfg2,
    751                Ip4Config2DataTypeManualAddress,
    752                SetAddressEvent
    753                );
    754     if (EFI_ERROR (Status)) {
    755       goto Exit;
    756     }
    757 
    758     //
    759     // Set gateway.
    760     //
    761     DataSize = Ip4NvData->GatewayAddressCount * sizeof (EFI_IPv4_ADDRESS);
    762     Status = Ip4Cfg2->SetData (
    763                         Ip4Cfg2,
    764                         Ip4Config2DataTypeGateway,
    765                         DataSize,
    766                         Ip4NvData->GatewayAddress
    767                         );
    768     if (EFI_ERROR (Status)) {
    769       goto Exit;
    770     }
    771 
    772     //
    773     // Set DNS addresses.
    774     //
    775     if (Ip4NvData->DnsAddressCount > 0 && Ip4NvData->DnsAddress != NULL) {
    776       DataSize = Ip4NvData->DnsAddressCount * sizeof (EFI_IPv4_ADDRESS);
    777       Status = Ip4Cfg2->SetData (
    778                           Ip4Cfg2,
    779                           Ip4Config2DataTypeDnsServer,
    780                           DataSize,
    781                           Ip4NvData->DnsAddress
    782                           );
    783 
    784       if (EFI_ERROR (Status)) {
    785         goto Exit;
    786       }
    787     }
    788   }
    789 
    790 Exit:
    791   if (SetAddressEvent != NULL) {
    792     gBS->CloseEvent (SetAddressEvent);
    793   }
    794 
    795   if (TimeoutEvent != NULL) {
    796     gBS->CloseEvent (TimeoutEvent);
    797   }
    798 
    799   return Status;
    800 }
    801 
    802 /**
    803   This function allows the caller to request the current
    804   configuration for one or more named elements. The resulting
    805   string is in <ConfigAltResp> format. Any and all alternative
    806   configuration strings shall also be appended to the end of the
    807   current configuration string. If they are, they must appear
    808   after the current configuration. They must contain the same
    809   routing (GUID, NAME, PATH) as the current configuration string.
    810   They must have an additional description indicating the type of
    811   alternative configuration the string represents,
    812   "ALTCFG=<StringToken>". That <StringToken> (when
    813   converted from Hex UNICODE to binary) is a reference to a
    814   string in the associated string pack.
    815 
    816   @param[in] This       Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    817   @param[in] Request    A null-terminated Unicode string in
    818                         <ConfigRequest> format. Note that this
    819                         includes the routing information as well as
    820                         the configurable name / value pairs. It is
    821                         invalid for this string to be in
    822                         <MultiConfigRequest> format.
    823   @param[out] Progress  On return, points to a character in the
    824                         Request string. Points to the string's null
    825                         terminator if request was successful. Points
    826                         to the most recent "&" before the first
    827                         failing name / value pair (or the beginning
    828                         of the string if the failure is in the first
    829                         name / value pair) if the request was not
    830                         successful.
    831   @param[out] Results   A null-terminated Unicode string in
    832                         <ConfigAltResp> format which has all values
    833                         filled in for the names in the Request string.
    834                         String to be allocated by the called function.
    835 
    836   @retval EFI_SUCCESS             The Results string is filled with the
    837                                   values corresponding to all requested
    838                                   names.
    839   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
    840                                   parts of the results that must be
    841                                   stored awaiting possible future
    842                                   protocols.
    843   @retval EFI_NOT_FOUND           Routing data doesn't match any
    844                                   known driver. Progress set to the
    845                                   first character in the routing header.
    846                                   Note: There is no requirement that the
    847                                   driver validate the routing data. It
    848                                   must skip the <ConfigHdr> in order to
    849                                   process the names.
    850   @retval EFI_INVALID_PARAMETER   Illegal syntax. Progress set
    851                                   to most recent & before the
    852                                   error or the beginning of the
    853                                   string.
    854   @retval EFI_INVALID_PARAMETER   Unknown name. Progress points
    855                                   to the & before the name in
    856                                   question.Currently not implemented.
    857 **/
    858 EFI_STATUS
    859 EFIAPI
    860 Ip4FormExtractConfig (
    861   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    862   IN  CONST EFI_STRING                       Request,
    863   OUT EFI_STRING                             *Progress,
    864   OUT EFI_STRING                             *Results
    865   )
    866 {
    867   EFI_STATUS                       Status;
    868   IP4_CONFIG2_INSTANCE             *Ip4Config2Instance;
    869   IP4_FORM_CALLBACK_INFO           *Private;
    870   IP4_CONFIG2_IFR_NVDATA           *IfrFormNvData;
    871   EFI_STRING                       ConfigRequestHdr;
    872   EFI_STRING                       ConfigRequest;
    873   BOOLEAN                          AllocatedRequest;
    874   EFI_STRING                       FormResult;
    875   UINTN                            Size;
    876   UINTN                            BufferSize;
    877 
    878   if (Progress == NULL || Results == NULL) {
    879     return EFI_INVALID_PARAMETER;
    880   }
    881 
    882   Status             = EFI_SUCCESS;
    883   IfrFormNvData      = NULL;
    884   ConfigRequest      = NULL;
    885   FormResult         = NULL;
    886   Size               = 0;
    887   AllocatedRequest   = FALSE;
    888   ConfigRequest      = Request;
    889   Private            = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
    890   Ip4Config2Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);
    891   BufferSize         = sizeof (IP4_CONFIG2_IFR_NVDATA);
    892   *Progress          = Request;
    893 
    894   //
    895   // Check Request data in <ConfigHdr>.
    896   //
    897   if ((Request == NULL) || HiiIsConfigHdrMatch (Request, &gIp4Config2NvDataGuid, mIp4Config2StorageName)) {
    898     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
    899     if (IfrFormNvData == NULL) {
    900       return EFI_OUT_OF_RESOURCES;
    901     }
    902 
    903     Ip4Config2ConvertConfigNvDataToIfrNvData (Ip4Config2Instance, IfrFormNvData);
    904 
    905     if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
    906       //
    907       // Request has no request element, construct full request string.
    908       // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
    909       // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
    910       //
    911       ConfigRequestHdr = HiiConstructConfigHdr (&gIp4Config2NvDataGuid, mIp4Config2StorageName, Private->ChildHandle);
    912       Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
    913       ConfigRequest = AllocateZeroPool (Size);
    914       ASSERT (ConfigRequest != NULL);
    915       AllocatedRequest = TRUE;
    916 
    917       UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
    918       FreePool (ConfigRequestHdr);
    919     }
    920 
    921     //
    922     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
    923     //
    924     Status = gHiiConfigRouting->BlockToConfig (
    925                                   gHiiConfigRouting,
    926                                   ConfigRequest,
    927                                   (UINT8 *) IfrFormNvData,
    928                                   BufferSize,
    929                                   &FormResult,
    930                                   Progress
    931                                   );
    932 
    933     FreePool (IfrFormNvData);
    934 
    935     //
    936     // Free the allocated config request string.
    937     //
    938     if (AllocatedRequest) {
    939       FreePool (ConfigRequest);
    940       ConfigRequest = NULL;
    941     }
    942 
    943     if (EFI_ERROR (Status)) {
    944       goto Failure;
    945     }
    946   }
    947 
    948   if (Request == NULL || HiiIsConfigHdrMatch (Request, &gIp4Config2NvDataGuid, mIp4Config2StorageName)) {
    949     *Results = FormResult;
    950   } else {
    951     return EFI_NOT_FOUND;
    952   }
    953 
    954 Failure:
    955   //
    956   // Set Progress string to the original request string.
    957   //
    958   if (Request == NULL) {
    959     *Progress = NULL;
    960   } else if (StrStr (Request, L"OFFSET") == NULL) {
    961     *Progress = Request + StrLen (Request);
    962   }
    963 
    964   return Status;
    965 }
    966 
    967 /**
    968   This function applies changes in a driver's configuration.
    969   Input is a Configuration, which has the routing data for this
    970   driver followed by name / value configuration pairs. The driver
    971   must apply those pairs to its configurable storage. If the
    972   driver's configuration is stored in a linear block of data
    973   and the driver's name / value pairs are in <BlockConfig>
    974   format, it may use the ConfigToBlock helper function (above) to
    975   simplify the job. Currently not implemented.
    976 
    977   @param[in]  This           Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    978   @param[in]  Configuration  A null-terminated Unicode string in
    979                              <ConfigString> format.
    980   @param[out] Progress       A pointer to a string filled in with the
    981                              offset of the most recent '&' before the
    982                              first failing name / value pair (or the
    983                              beginn ing of the string if the failure
    984                              is in the first name / value pair) or
    985                              the terminating NULL if all was
    986                              successful.
    987 
    988   @retval EFI_SUCCESS             The results have been distributed or are
    989                                   awaiting distribution.
    990   @retval EFI_OUT_OF_MEMORY       Not enough memory to store the
    991                                   parts of the results that must be
    992                                   stored awaiting possible future
    993                                   protocols.
    994   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
    995                                   Results parameter would result
    996                                   in this type of error.
    997   @retval EFI_NOT_FOUND           Target for the specified routing data
    998                                   was not found.
    999 **/
   1000 EFI_STATUS
   1001 EFIAPI
   1002 Ip4FormRouteConfig (
   1003   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1004   IN  CONST EFI_STRING                       Configuration,
   1005   OUT EFI_STRING                             *Progress
   1006   )
   1007 {
   1008   EFI_STATUS                       Status;
   1009   UINTN                            BufferSize;
   1010   IP4_CONFIG2_IFR_NVDATA           *IfrFormNvData;
   1011   IP4_CONFIG2_INSTANCE             *Ip4Config2Instance;
   1012   IP4_FORM_CALLBACK_INFO           *Private;
   1013 
   1014   Status        = EFI_SUCCESS;
   1015   IfrFormNvData = NULL;
   1016 
   1017   if (Configuration == NULL || Progress == NULL) {
   1018     return EFI_INVALID_PARAMETER;
   1019   }
   1020 
   1021   *Progress = Configuration;
   1022 
   1023   Private            = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
   1024   Ip4Config2Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);
   1025 
   1026   //
   1027   // Check Routing data in <ConfigHdr>.
   1028   //
   1029   if (HiiIsConfigHdrMatch (Configuration, &gIp4Config2NvDataGuid, mIp4Config2StorageName)) {
   1030     //
   1031     // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
   1032     //
   1033     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
   1034     if (IfrFormNvData == NULL) {
   1035       return EFI_OUT_OF_RESOURCES;
   1036     }
   1037 
   1038     BufferSize = 0;
   1039 
   1040     Status = gHiiConfigRouting->ConfigToBlock (
   1041                                   gHiiConfigRouting,
   1042                                   Configuration,
   1043                                   (UINT8 *) IfrFormNvData,
   1044                                   &BufferSize,
   1045                                   Progress
   1046                                   );
   1047     if (Status != EFI_BUFFER_TOO_SMALL) {
   1048       return Status;
   1049     }
   1050 
   1051     Status = gHiiConfigRouting->ConfigToBlock (
   1052                                   gHiiConfigRouting,
   1053                                   Configuration,
   1054                                   (UINT8 *) IfrFormNvData,
   1055                                   &BufferSize,
   1056                                   Progress
   1057                                   );
   1058     if (!EFI_ERROR (Status)) {
   1059       Status = Ip4Config2ConvertIfrNvDataToConfigNvData (IfrFormNvData, Ip4Config2Instance);
   1060     }
   1061 
   1062     FreePool (IfrFormNvData);
   1063   } else {
   1064     return EFI_NOT_FOUND;
   1065   }
   1066 
   1067   return Status;
   1068 
   1069 }
   1070 
   1071 /**
   1072   This function is called to provide results data to the driver.
   1073   This data consists of a unique key that is used to identify
   1074   which data is either being passed back or being asked for.
   1075 
   1076   @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1077   @param[in]  Action             Specifies the type of action taken by the browser.
   1078   @param[in]  QuestionId         A unique value which is sent to the original
   1079                                  exporting driver so that it can identify the type
   1080                                  of data to expect. The format of the data tends to
   1081                                  vary based on the opcode that enerated the callback.
   1082   @param[in]  Type               The type of value for the question.
   1083   @param[in]  Value              A pointer to the data being sent to the original
   1084                                  exporting driver.
   1085   @param[out] ActionRequest      On return, points to the action requested by the
   1086                                  callback function.
   1087 
   1088   @retval EFI_SUCCESS            The callback successfully handled the action.
   1089   @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
   1090                                  variable and its data.
   1091   @retval EFI_DEVICE_ERROR       The variable could not be saved.
   1092   @retval EFI_UNSUPPORTED        The specified Action is not supported by the
   1093                                  callback.Currently not implemented.
   1094   @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
   1095   @retval Others                 Other errors as indicated.
   1096 
   1097 **/
   1098 EFI_STATUS
   1099 EFIAPI
   1100 Ip4FormCallback (
   1101   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
   1102   IN  EFI_BROWSER_ACTION                     Action,
   1103   IN  EFI_QUESTION_ID                        QuestionId,
   1104   IN  UINT8                                  Type,
   1105   IN  EFI_IFR_TYPE_VALUE                     *Value,
   1106   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
   1107   )
   1108 {
   1109   EFI_STATUS                Status;
   1110   IP4_CONFIG2_INSTANCE      *Instance;
   1111   IP4_CONFIG2_IFR_NVDATA    *IfrFormNvData;
   1112   IP4_FORM_CALLBACK_INFO    *Private;
   1113 
   1114   EFI_IP_ADDRESS            StationAddress;
   1115   EFI_IP_ADDRESS            SubnetMask;
   1116   EFI_IP_ADDRESS            Gateway;
   1117   IP4_ADDR                  Ip;
   1118   EFI_IPv4_ADDRESS          *DnsAddress;
   1119   UINTN                     DnsCount;
   1120   UINTN                     Index;
   1121   EFI_INPUT_KEY             Key;
   1122 
   1123   IfrFormNvData = NULL;
   1124   DnsCount      = 0;
   1125   DnsAddress    = NULL;
   1126 
   1127   if (Action == EFI_BROWSER_ACTION_CHANGED) {
   1128     Private = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
   1129     Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);
   1130 
   1131     IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
   1132     if (IfrFormNvData == NULL) {
   1133       return EFI_OUT_OF_RESOURCES;
   1134     }
   1135 
   1136     //
   1137     // Retrieve uncommitted data from Browser
   1138     //
   1139     if (!HiiGetBrowserData (&gIp4Config2NvDataGuid, mIp4Config2StorageName, sizeof (IP4_CONFIG2_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {
   1140       FreePool (IfrFormNvData);
   1141       return EFI_NOT_FOUND;
   1142     }
   1143 
   1144     Status = EFI_SUCCESS;
   1145 
   1146     switch (QuestionId) {
   1147     case KEY_LOCAL_IP:
   1148       Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
   1149       if (EFI_ERROR (Status) || IP4_IS_UNSPECIFIED (NTOHL (StationAddress.Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (StationAddress.Addr[0]))) {
   1150         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
   1151         Status = EFI_INVALID_PARAMETER;
   1152       }
   1153       break;
   1154 
   1155     case KEY_SUBNET_MASK:
   1156       Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
   1157       if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
   1158         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
   1159         Status = EFI_INVALID_PARAMETER;
   1160       }
   1161       break;
   1162 
   1163     case KEY_GATE_WAY:
   1164       Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
   1165       if (EFI_ERROR (Status) || IP4_IS_LOCAL_BROADCAST(NTOHL(Gateway.Addr[0]))) {
   1166         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
   1167         Status = EFI_INVALID_PARAMETER;
   1168       }
   1169       break;
   1170 
   1171     case KEY_DNS:
   1172       Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
   1173       if (!EFI_ERROR (Status) && DnsCount > 0) {
   1174         for (Index = 0; Index < DnsCount; Index ++) {
   1175           CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
   1176           if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
   1177             CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
   1178             Status = EFI_INVALID_PARAMETER;
   1179             break;
   1180           }
   1181         }
   1182       } else {
   1183         if (EFI_ERROR (Status)) {
   1184           CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
   1185         }
   1186       }
   1187 
   1188       if(DnsAddress != NULL) {
   1189         FreePool(DnsAddress);
   1190       }
   1191       break;
   1192 
   1193     case KEY_SAVE_CHANGES:
   1194       Status = Ip4Config2ConvertIfrNvDataToConfigNvData (IfrFormNvData, Instance);
   1195       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
   1196       break;
   1197 
   1198     default:
   1199       break;
   1200     }
   1201 
   1202     FreePool (IfrFormNvData);
   1203 
   1204     return Status;
   1205   }
   1206 
   1207   //
   1208   // All other action return unsupported.
   1209   //
   1210   return EFI_UNSUPPORTED;
   1211 }
   1212 
   1213 /**
   1214   Install HII Config Access protocol for network device and allocate resource.
   1215 
   1216   @param[in, out]  Instance        The IP4 config2 Instance.
   1217 
   1218   @retval EFI_SUCCESS              The HII Config Access protocol is installed.
   1219   @retval EFI_OUT_OF_RESOURCES     Failed to allocate memory.
   1220   @retval Others                   Other errors as indicated.
   1221 
   1222 **/
   1223 EFI_STATUS
   1224 Ip4Config2FormInit (
   1225   IN OUT IP4_CONFIG2_INSTANCE     *Instance
   1226   )
   1227 {
   1228   EFI_STATUS                     Status;
   1229   IP4_SERVICE                    *IpSb;
   1230   IP4_FORM_CALLBACK_INFO         *CallbackInfo;
   1231   EFI_HII_CONFIG_ACCESS_PROTOCOL *ConfigAccess;
   1232   VENDOR_DEVICE_PATH             VendorDeviceNode;
   1233   EFI_SERVICE_BINDING_PROTOCOL   *MnpSb;
   1234   CHAR16                         *MacString;
   1235   CHAR16                         MenuString[128];
   1236   CHAR16                         PortString[128];
   1237   CHAR16                         *OldMenuString;
   1238   EFI_DEVICE_PATH_PROTOCOL       *ParentDevicePath;
   1239 
   1240   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1241   ASSERT (IpSb != NULL);
   1242 
   1243   CallbackInfo = &Instance->CallbackInfo;
   1244 
   1245   CallbackInfo->Signature = IP4_FORM_CALLBACK_INFO_SIGNATURE;
   1246 
   1247   Status = gBS->HandleProtocol (
   1248                   IpSb->Controller,
   1249                   &gEfiDevicePathProtocolGuid,
   1250                   (VOID **) &ParentDevicePath
   1251                   );
   1252   if (EFI_ERROR (Status)) {
   1253     return Status;
   1254   }
   1255 
   1256   //
   1257   // Construct device path node for EFI HII Config Access protocol,
   1258   // which consists of controller physical device path and one hardware
   1259   // vendor guid node.
   1260   //
   1261   ZeroMem (&VendorDeviceNode, sizeof (VENDOR_DEVICE_PATH));
   1262   VendorDeviceNode.Header.Type    = HARDWARE_DEVICE_PATH;
   1263   VendorDeviceNode.Header.SubType = HW_VENDOR_DP;
   1264 
   1265   CopyGuid (&VendorDeviceNode.Guid, &gEfiCallerIdGuid);
   1266 
   1267   SetDevicePathNodeLength (&VendorDeviceNode.Header, sizeof (VENDOR_DEVICE_PATH));
   1268   CallbackInfo->HiiVendorDevicePath = AppendDevicePathNode (
   1269                                         ParentDevicePath,
   1270                                         (EFI_DEVICE_PATH_PROTOCOL *) &VendorDeviceNode
   1271                                         );
   1272   if (CallbackInfo->HiiVendorDevicePath == NULL) {
   1273     Status = EFI_OUT_OF_RESOURCES;
   1274     goto Error;
   1275   }
   1276 
   1277   ConfigAccess                = &CallbackInfo->HiiConfigAccessProtocol;
   1278   ConfigAccess->ExtractConfig = Ip4FormExtractConfig;
   1279   ConfigAccess->RouteConfig   = Ip4FormRouteConfig;
   1280   ConfigAccess->Callback      = Ip4FormCallback;
   1281 
   1282   //
   1283   // Install Device Path Protocol and Config Access protocol on new handle
   1284   //
   1285   Status = gBS->InstallMultipleProtocolInterfaces (
   1286                   &CallbackInfo->ChildHandle,
   1287                   &gEfiDevicePathProtocolGuid,
   1288                   CallbackInfo->HiiVendorDevicePath,
   1289                   &gEfiHiiConfigAccessProtocolGuid,
   1290                   ConfigAccess,
   1291                   NULL
   1292                   );
   1293 
   1294   if (!EFI_ERROR (Status)) {
   1295     //
   1296     // Open the Parent Handle for the child
   1297     //
   1298     Status = gBS->OpenProtocol (
   1299                     IpSb->Controller,
   1300                     &gEfiManagedNetworkServiceBindingProtocolGuid,
   1301                     (VOID **) &MnpSb,
   1302                     IpSb->Image,
   1303                     CallbackInfo->ChildHandle,
   1304                     EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
   1305                     );
   1306   }
   1307 
   1308   if (EFI_ERROR (Status)) {
   1309     goto Error;
   1310   }
   1311 
   1312   //
   1313   // Publish our HII data
   1314   //
   1315   CallbackInfo->RegisteredHandle = HiiAddPackages (
   1316                                      &gIp4Config2NvDataGuid,
   1317                                      CallbackInfo->ChildHandle,
   1318                                      Ip4DxeStrings,
   1319                                      Ip4Config2Bin,
   1320                                      NULL
   1321                                      );
   1322   if (CallbackInfo->RegisteredHandle == NULL) {
   1323     Status = EFI_OUT_OF_RESOURCES;
   1324     goto Error;
   1325   }
   1326 
   1327   //
   1328   // Append MAC string in the menu help string and tile help string
   1329   //
   1330   Status = NetLibGetMacString (IpSb->Controller, IpSb->Image, &MacString);
   1331   if (!EFI_ERROR (Status)) {
   1332     OldMenuString = HiiGetString (
   1333                       CallbackInfo->RegisteredHandle,
   1334                       STRING_TOKEN (STR_IP4_CONFIG2_FORM_HELP),
   1335                       NULL
   1336                       );
   1337     UnicodeSPrint (MenuString, 128, L"%s (MAC:%s)", OldMenuString, MacString);
   1338     HiiSetString (
   1339       CallbackInfo->RegisteredHandle,
   1340       STRING_TOKEN (STR_IP4_CONFIG2_FORM_HELP),
   1341       MenuString,
   1342       NULL
   1343       );
   1344 
   1345     UnicodeSPrint (PortString, 128, L"MAC:%s", MacString);
   1346     HiiSetString (
   1347       CallbackInfo->RegisteredHandle,
   1348       STRING_TOKEN (STR_IP4_DEVICE_FORM_HELP),
   1349       PortString,
   1350       NULL
   1351       );
   1352 
   1353     FreePool (MacString);
   1354     FreePool (OldMenuString);
   1355 
   1356     return EFI_SUCCESS;
   1357   }
   1358 
   1359 Error:
   1360   Ip4Config2FormUnload (Instance);
   1361   return Status;
   1362 }
   1363 
   1364 /**
   1365   Uninstall the HII Config Access protocol for network devices and free up the resources.
   1366 
   1367   @param[in, out]  Instance      The IP4 config2 instance to unload a form.
   1368 
   1369 **/
   1370 VOID
   1371 Ip4Config2FormUnload (
   1372   IN OUT IP4_CONFIG2_INSTANCE     *Instance
   1373   )
   1374 {
   1375   IP4_SERVICE                    *IpSb;
   1376   IP4_FORM_CALLBACK_INFO         *CallbackInfo;
   1377   IP4_CONFIG2_NVDATA             *Ip4NvData;
   1378 
   1379   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1380   ASSERT (IpSb != NULL);
   1381 
   1382   CallbackInfo = &Instance->CallbackInfo;
   1383 
   1384   if (CallbackInfo->ChildHandle != NULL) {
   1385     //
   1386     // Close the child handle
   1387     //
   1388     gBS->CloseProtocol (
   1389            IpSb->Controller,
   1390            &gEfiManagedNetworkServiceBindingProtocolGuid,
   1391            IpSb->Image,
   1392            CallbackInfo->ChildHandle
   1393            );
   1394 
   1395     //
   1396     // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL
   1397     //
   1398     gBS->UninstallMultipleProtocolInterfaces (
   1399            CallbackInfo->ChildHandle,
   1400            &gEfiDevicePathProtocolGuid,
   1401            CallbackInfo->HiiVendorDevicePath,
   1402            &gEfiHiiConfigAccessProtocolGuid,
   1403            &CallbackInfo->HiiConfigAccessProtocol,
   1404            NULL
   1405            );
   1406   }
   1407 
   1408   if (CallbackInfo->HiiVendorDevicePath != NULL) {
   1409     FreePool (CallbackInfo->HiiVendorDevicePath);
   1410   }
   1411 
   1412   if (CallbackInfo->RegisteredHandle != NULL) {
   1413     //
   1414     // Remove HII package list
   1415     //
   1416     HiiRemovePackages (CallbackInfo->RegisteredHandle);
   1417   }
   1418 
   1419   Ip4NvData = &Instance->Ip4NvData;
   1420 
   1421   if(Ip4NvData->ManualAddress != NULL) {
   1422     FreePool(Ip4NvData->ManualAddress);
   1423   }
   1424 
   1425   if(Ip4NvData->GatewayAddress != NULL) {
   1426     FreePool(Ip4NvData->GatewayAddress);
   1427   }
   1428 
   1429   if(Ip4NvData->DnsAddress != NULL) {
   1430     FreePool(Ip4NvData->DnsAddress);
   1431   }
   1432 
   1433   Ip4NvData->ManualAddressCount  = 0;
   1434   Ip4NvData->GatewayAddressCount = 0;
   1435   Ip4NvData->DnsAddressCount     = 0;
   1436 }
   1437