Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2   The implementation of EFI IPv4 Configuration II Protocol.
      3 
      4   Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
      5   (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
      6 
      7   This program and the accompanying materials
      8   are licensed and made available under the terms and conditions of the BSD License
      9   which accompanies this distribution.  The full text of the license may be found at
     10   http://opensource.org/licenses/bsd-license.php.
     11 
     12   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "Ip4Impl.h"
     18 
     19 LIST_ENTRY  mIp4Config2InstanceList = {&mIp4Config2InstanceList, &mIp4Config2InstanceList};
     20 
     21 /**
     22   The event process routine when the DHCPv4 service binding protocol is installed
     23   in the system.
     24 
     25   @param[in]     Event         Not used.
     26   @param[in]     Context       Pointer to the IP4 config2 instance data.
     27 
     28 **/
     29 VOID
     30 EFIAPI
     31 Ip4Config2OnDhcp4SbInstalled (
     32   IN EFI_EVENT  Event,
     33   IN VOID       *Context
     34   );
     35 
     36 /**
     37   Destroy the Dhcp4 child in IP4_CONFIG2_INSTANCE and release the resources.
     38 
     39   @param[in, out] Instance    The buffer of IP4 config2 instance to be freed.
     40 
     41   @retval EFI_SUCCESS         The child was successfully destroyed.
     42   @retval Others              Failed to destroy the child.
     43 
     44 **/
     45 EFI_STATUS
     46 Ip4Config2DestroyDhcp4 (
     47   IN OUT IP4_CONFIG2_INSTANCE  *Instance
     48   )
     49 {
     50   IP4_SERVICE                 *IpSb;
     51   EFI_STATUS                  Status;
     52   EFI_DHCP4_PROTOCOL          *Dhcp4;
     53 
     54   Dhcp4 = Instance->Dhcp4;
     55   ASSERT (Dhcp4 != NULL);
     56 
     57   Dhcp4->Stop (Dhcp4);
     58   Dhcp4->Configure (Dhcp4, NULL);
     59   Instance->Dhcp4 = NULL;
     60 
     61   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
     62 
     63   //
     64   // Close DHCPv4 protocol and destroy the child.
     65   //
     66   Status = gBS->CloseProtocol (
     67                   Instance->Dhcp4Handle,
     68                   &gEfiDhcp4ProtocolGuid,
     69                   IpSb->Image,
     70                   IpSb->Controller
     71                   );
     72   if (EFI_ERROR (Status)) {
     73     return Status;
     74   }
     75 
     76   Status = NetLibDestroyServiceChild (
     77              IpSb->Controller,
     78              IpSb->Image,
     79              &gEfiDhcp4ServiceBindingProtocolGuid,
     80              Instance->Dhcp4Handle
     81              );
     82 
     83   Instance->Dhcp4Handle = NULL;
     84 
     85   return Status;
     86 }
     87 
     88 /**
     89   Update the current policy to NewPolicy. During the transition
     90   period, the default router list
     91   and address list in all interfaces will be released.
     92 
     93   @param[in]  IpSb               The IP4 service binding instance.
     94   @param[in]  NewPolicy          The new policy to be updated to.
     95 
     96 **/
     97 VOID
     98 Ip4Config2OnPolicyChanged (
     99   IN IP4_SERVICE            *IpSb,
    100   IN EFI_IP4_CONFIG2_POLICY NewPolicy
    101   )
    102 {
    103   IP4_INTERFACE   *IpIf;
    104   IP4_ROUTE_TABLE *RouteTable;
    105 
    106   //
    107   // Currently there are only two policies: static and dhcp. Regardless of
    108   // what transition is going on, i.e., static -> dhcp and dhcp ->
    109   // static, we have to free default router table and all addresses.
    110   //
    111 
    112   if (IpSb->DefaultInterface != NULL) {
    113     if (IpSb->DefaultRouteTable != NULL) {
    114       Ip4FreeRouteTable (IpSb->DefaultRouteTable);
    115       IpSb->DefaultRouteTable = NULL;
    116     }
    117 
    118     Ip4CancelReceive (IpSb->DefaultInterface);
    119 
    120     Ip4FreeInterface (IpSb->DefaultInterface, NULL);
    121     IpSb->DefaultInterface = NULL;
    122   }
    123 
    124   Ip4CleanAssembleTable (&IpSb->Assemble);
    125 
    126   //
    127   // Create new default interface and route table.
    128   //
    129   IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
    130   if (IpIf == NULL) {
    131     return ;
    132   }
    133 
    134   RouteTable = Ip4CreateRouteTable ();
    135   if (RouteTable == NULL) {
    136     Ip4FreeInterface (IpIf, NULL);
    137     return ;
    138   }
    139 
    140   IpSb->DefaultInterface  = IpIf;
    141   InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
    142   IpSb->DefaultRouteTable = RouteTable;
    143   Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
    144 
    145   if (IpSb->State == IP4_SERVICE_CONFIGED) {
    146     IpSb->State = IP4_SERVICE_UNSTARTED;
    147   }
    148 
    149   //
    150   // Start the dhcp configuration.
    151   //
    152   if (NewPolicy == Ip4Config2PolicyDhcp) {
    153     IpSb->Reconfig = TRUE;
    154     Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);
    155   }
    156 
    157 }
    158 
    159 /**
    160   Signal the registered event. It is the callback routine for NetMapIterate.
    161 
    162   @param[in]  Map    Points to the list of registered event.
    163   @param[in]  Item   The registered event.
    164   @param[in]  Arg    Not used.
    165 
    166   @retval EFI_SUCCESS           The event was signaled successfully.
    167 **/
    168 EFI_STATUS
    169 EFIAPI
    170 Ip4Config2SignalEvent (
    171   IN NET_MAP                *Map,
    172   IN NET_MAP_ITEM           *Item,
    173   IN VOID                   *Arg
    174   )
    175 {
    176   gBS->SignalEvent ((EFI_EVENT) Item->Key);
    177 
    178   return EFI_SUCCESS;
    179 }
    180 
    181 /**
    182   Read the configuration data from variable storage according to the VarName and
    183   gEfiIp4Config2ProtocolGuid. It checks the integrity of variable data. If the
    184   data is corrupted, it clears the variable data to ZERO. Othewise, it outputs the
    185   configuration data to IP4_CONFIG2_INSTANCE.
    186 
    187   @param[in]      VarName       The pointer to the variable name
    188   @param[in, out] Instance      The pointer to the IP4 config2 instance data.
    189 
    190   @retval EFI_NOT_FOUND         The variable can not be found or already corrupted.
    191   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
    192   @retval EFI_SUCCESS           The configuration data was retrieved successfully.
    193 
    194 **/
    195 EFI_STATUS
    196 Ip4Config2ReadConfigData (
    197   IN     CHAR16               *VarName,
    198   IN OUT IP4_CONFIG2_INSTANCE *Instance
    199   )
    200 {
    201   EFI_STATUS              Status;
    202   UINTN                   VarSize;
    203   IP4_CONFIG2_VARIABLE    *Variable;
    204   IP4_CONFIG2_DATA_ITEM   *DataItem;
    205   UINTN                   Index;
    206   IP4_CONFIG2_DATA_RECORD DataRecord;
    207   CHAR8                   *Data;
    208 
    209   //
    210   // Try to read the configuration variable.
    211   //
    212   VarSize = 0;
    213   Status  = gRT->GetVariable (
    214                    VarName,
    215                    &gEfiIp4Config2ProtocolGuid,
    216                    NULL,
    217                    &VarSize,
    218                    NULL
    219                    );
    220 
    221   if (Status == EFI_BUFFER_TOO_SMALL) {
    222     //
    223     // Allocate buffer and read the config variable.
    224     //
    225     Variable = AllocatePool (VarSize);
    226     if (Variable == NULL) {
    227       return EFI_OUT_OF_RESOURCES;
    228     }
    229 
    230     Status = gRT->GetVariable (
    231                     VarName,
    232                     &gEfiIp4Config2ProtocolGuid,
    233                     NULL,
    234                     &VarSize,
    235                     Variable
    236                     );
    237     if (EFI_ERROR (Status) || (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize)) != 0) {
    238       //
    239       // GetVariable still error or the variable is corrupted.
    240       // Fall back to the default value.
    241       //
    242       FreePool (Variable);
    243 
    244       //
    245       // Remove the problematic variable and return EFI_NOT_FOUND, a new
    246       // variable will be set again.
    247       //
    248       gRT->SetVariable (
    249              VarName,
    250              &gEfiIp4Config2ProtocolGuid,
    251              IP4_CONFIG2_VARIABLE_ATTRIBUTE,
    252              0,
    253              NULL
    254              );
    255 
    256       return EFI_NOT_FOUND;
    257     }
    258 
    259 
    260     for (Index = 0; Index < Variable->DataRecordCount; Index++) {
    261 
    262       CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));
    263 
    264       DataItem = &Instance->DataItem[DataRecord.DataType];
    265       if (DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED) &&
    266           (DataItem->DataSize != DataRecord.DataSize)
    267           ) {
    268         //
    269         // Perhaps a corrupted data record...
    270         //
    271         continue;
    272       }
    273 
    274       if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
    275         //
    276         // This data item has variable length data.
    277         //
    278         DataItem->Data.Ptr = AllocatePool (DataRecord.DataSize);
    279         if (DataItem->Data.Ptr == NULL) {
    280           //
    281           // no memory resource
    282           //
    283           continue;
    284         }
    285       }
    286 
    287       Data = (CHAR8 *) Variable + DataRecord.Offset;
    288       CopyMem (DataItem->Data.Ptr, Data, DataRecord.DataSize);
    289 
    290       DataItem->DataSize = DataRecord.DataSize;
    291       DataItem->Status   = EFI_SUCCESS;
    292     }
    293 
    294     FreePool (Variable);
    295     return EFI_SUCCESS;
    296   }
    297 
    298   return Status;
    299 }
    300 
    301 /**
    302   Write the configuration data from IP4_CONFIG2_INSTANCE to variable storage.
    303 
    304   @param[in]      VarName       The pointer to the variable name.
    305   @param[in]      Instance      The pointer to the IP4 config2 instance data.
    306 
    307   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
    308   @retval EFI_SUCCESS           The configuration data is written successfully.
    309 
    310 **/
    311 EFI_STATUS
    312 Ip4Config2WriteConfigData (
    313   IN CHAR16               *VarName,
    314   IN IP4_CONFIG2_INSTANCE *Instance
    315   )
    316 {
    317   UINTN                   Index;
    318   UINTN                   VarSize;
    319   IP4_CONFIG2_DATA_ITEM   *DataItem;
    320   IP4_CONFIG2_VARIABLE    *Variable;
    321   IP4_CONFIG2_DATA_RECORD *DataRecord;
    322   CHAR8                   *Heap;
    323   EFI_STATUS              Status;
    324 
    325   VarSize = sizeof (IP4_CONFIG2_VARIABLE) - sizeof (IP4_CONFIG2_DATA_RECORD);
    326 
    327   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
    328 
    329     DataItem = &Instance->DataItem[Index];
    330     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
    331 
    332       VarSize += sizeof (IP4_CONFIG2_DATA_RECORD) + DataItem->DataSize;
    333     }
    334   }
    335 
    336   Variable = AllocatePool (VarSize);
    337   if (Variable == NULL) {
    338     return EFI_OUT_OF_RESOURCES;
    339   }
    340 
    341   Heap                      = (CHAR8 *) Variable + VarSize;
    342   Variable->DataRecordCount = 0;
    343 
    344   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
    345 
    346     DataItem = &Instance->DataItem[Index];
    347     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {
    348 
    349       Heap -= DataItem->DataSize;
    350       CopyMem (Heap, DataItem->Data.Ptr, DataItem->DataSize);
    351 
    352       DataRecord           = &Variable->DataRecord[Variable->DataRecordCount];
    353       DataRecord->DataType = (EFI_IP4_CONFIG2_DATA_TYPE) Index;
    354       DataRecord->DataSize = (UINT32) DataItem->DataSize;
    355       DataRecord->Offset   = (UINT16) (Heap - (CHAR8 *) Variable);
    356 
    357       Variable->DataRecordCount++;
    358     }
    359   }
    360 
    361   Variable->Checksum = 0;
    362   Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize);
    363 
    364   Status = gRT->SetVariable (
    365                   VarName,
    366                   &gEfiIp4Config2ProtocolGuid,
    367                   IP4_CONFIG2_VARIABLE_ATTRIBUTE,
    368                   VarSize,
    369                   Variable
    370                   );
    371 
    372   FreePool (Variable);
    373 
    374   return Status;
    375 }
    376 
    377 
    378 /**
    379   Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of GetModeData.
    380   The EFI_IP4_ROUTE_TABLE is clumsy to use in the internal operation of the
    381   IP4 driver.
    382 
    383   @param[in]   IpSb        The IP4 service binding instance.
    384   @param[out]  Table       The built IP4 route table.
    385 
    386   @retval EFI_SUCCESS           The route table is successfully build
    387   @retval EFI_NOT_FOUND         Failed to allocate the memory for the rotue table.
    388 
    389 **/
    390 EFI_STATUS
    391 Ip4Config2BuildDefaultRouteTable (
    392   IN  IP4_SERVICE               *IpSb,
    393   OUT EFI_IP4_ROUTE_TABLE       *Table
    394   )
    395 {
    396   LIST_ENTRY                *Entry;
    397   IP4_ROUTE_ENTRY           *RtEntry;
    398   UINT32                    Count;
    399   INT32                     Index;
    400 
    401   if (IpSb->DefaultRouteTable == NULL) {
    402     return EFI_NOT_FOUND;
    403   }
    404 
    405   Count = IpSb->DefaultRouteTable->TotalNum;
    406 
    407   if (Count == 0) {
    408     return EFI_NOT_FOUND;
    409   }
    410 
    411   //
    412   // Copy the route entry to EFI route table. Keep the order of
    413   // route entry copied from most specific to default route. That
    414   // is, interlevel the route entry from the instance's route area
    415   // and those from the default route table's route area.
    416   //
    417   Count = 0;
    418 
    419   for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {
    420 
    421     NET_LIST_FOR_EACH (Entry, &(IpSb->DefaultRouteTable->RouteArea[Index])) {
    422       RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);
    423 
    424       EFI_IP4 (Table[Count].SubnetAddress)  = HTONL (RtEntry->Dest & RtEntry->Netmask);
    425       EFI_IP4 (Table[Count].SubnetMask)     = HTONL (RtEntry->Netmask);
    426       EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);
    427 
    428       Count++;
    429     }
    430 
    431   }
    432 
    433   return EFI_SUCCESS;
    434 }
    435 
    436 /**
    437   The event process routine when the DHCPv4 service binding protocol is installed
    438   in the system.
    439 
    440   @param[in]     Event         Not used.
    441   @param[in]     Context       The pointer to the IP4 config2 instance data.
    442 
    443 **/
    444 VOID
    445 EFIAPI
    446 Ip4Config2OnDhcp4SbInstalled (
    447   IN EFI_EVENT  Event,
    448   IN VOID       *Context
    449   )
    450 {
    451   IP4_CONFIG2_INSTANCE  *Instance;
    452 
    453   Instance = (IP4_CONFIG2_INSTANCE *) Context;
    454 
    455   if ((Instance->Dhcp4Handle != NULL) || (Instance->Policy != Ip4Config2PolicyDhcp)) {
    456     //
    457     // The DHCP4 child is already created or the policy is no longer DHCP.
    458     //
    459     return ;
    460   }
    461 
    462   Ip4StartAutoConfig (Instance);
    463 }
    464 
    465 /**
    466   Set the station address and subnetmask for the default interface.
    467 
    468   @param[in]  IpSb               The pointer to the IP4 service binding instance.
    469   @param[in]  StationAddress     Ip address to be set.
    470   @param[in]  SubnetMask         Subnet to be set.
    471 
    472   @retval EFI_SUCCESS   Set default address successful.
    473   @retval Others        Some errors occur in setting.
    474 
    475 **/
    476 EFI_STATUS
    477 Ip4Config2SetDefaultAddr (
    478   IN IP4_SERVICE            *IpSb,
    479   IN IP4_ADDR               StationAddress,
    480   IN IP4_ADDR               SubnetMask
    481   )
    482 {
    483   EFI_STATUS                Status;
    484   IP4_INTERFACE             *IpIf;
    485   IP4_PROTOCOL              *Ip4Instance;
    486   EFI_ARP_PROTOCOL          *Arp;
    487   LIST_ENTRY                *Entry;
    488   IP4_ADDR                  Subnet;
    489   IP4_ROUTE_TABLE           *RouteTable;
    490 
    491   IpIf = IpSb->DefaultInterface;
    492   ASSERT (IpIf != NULL);
    493 
    494   if ((IpIf->Ip == StationAddress) && (IpIf->SubnetMask == SubnetMask)) {
    495     IpSb->State = IP4_SERVICE_CONFIGED;
    496     return EFI_SUCCESS;
    497   }
    498 
    499   if (IpSb->Reconfig) {
    500     //
    501     // The default address is changed, free the previous interface first.
    502     //
    503     if (IpSb->DefaultRouteTable != NULL) {
    504       Ip4FreeRouteTable (IpSb->DefaultRouteTable);
    505       IpSb->DefaultRouteTable = NULL;
    506     }
    507 
    508     Ip4CancelReceive (IpSb->DefaultInterface);
    509     Ip4FreeInterface (IpSb->DefaultInterface, NULL);
    510     IpSb->DefaultInterface = NULL;
    511     //
    512     // Create new default interface and route table.
    513     //
    514     IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);
    515     if (IpIf == NULL) {
    516       return EFI_OUT_OF_RESOURCES;
    517     }
    518 
    519     RouteTable = Ip4CreateRouteTable ();
    520     if (RouteTable == NULL) {
    521       Ip4FreeInterface (IpIf, NULL);
    522       return EFI_OUT_OF_RESOURCES;
    523     }
    524 
    525     IpSb->DefaultInterface  = IpIf;
    526     InsertHeadList (&IpSb->Interfaces, &IpIf->Link);
    527     IpSb->DefaultRouteTable = RouteTable;
    528     Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);
    529   }
    530 
    531   if (IpSb->State == IP4_SERVICE_CONFIGED) {
    532     IpSb->State = IP4_SERVICE_UNSTARTED;
    533   }
    534 
    535   Status = Ip4SetAddress (IpIf, StationAddress, SubnetMask);
    536   if (EFI_ERROR (Status)) {
    537     return Status;
    538   }
    539 
    540   if (IpIf->Arp != NULL) {
    541     //
    542     // A non-NULL IpIf->Arp here means a new ARP child is created when setting default address,
    543     // but some IP children may have referenced the default interface before it is configured,
    544     // these IP instances also consume this ARP protocol so they need to open it BY_CHILD_CONTROLLER.
    545     //
    546     Arp = NULL;
    547     NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {
    548       Ip4Instance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, AddrLink, IP4_PROTOCOL_SIGNATURE);
    549       Status = gBS->OpenProtocol (
    550                       IpIf->ArpHandle,
    551                       &gEfiArpProtocolGuid,
    552                       (VOID **) &Arp,
    553                       gIp4DriverBinding.DriverBindingHandle,
    554                       Ip4Instance->Handle,
    555                       EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
    556                       );
    557       if (EFI_ERROR (Status)) {
    558         return Status;
    559       }
    560     }
    561   }
    562 
    563   Ip4AddRoute (
    564     IpSb->DefaultRouteTable,
    565     StationAddress,
    566     SubnetMask,
    567     IP4_ALLZERO_ADDRESS
    568     );
    569 
    570   //
    571   // Add a route for the connected network.
    572   //
    573   Subnet = StationAddress & SubnetMask;
    574 
    575   Ip4AddRoute (
    576     IpSb->DefaultRouteTable,
    577     Subnet,
    578     SubnetMask,
    579     IP4_ALLZERO_ADDRESS
    580     );
    581 
    582   IpSb->State = IP4_SERVICE_CONFIGED;
    583   IpSb->Reconfig = FALSE;
    584 
    585   return EFI_SUCCESS;
    586 }
    587 
    588 /**
    589   Set the station address, subnetmask and gateway address for the default interface.
    590 
    591   @param[in]  Instance         The pointer to the IP4 config2 instance data.
    592   @param[in]  StationAddress   Ip address to be set.
    593   @param[in]  SubnetMask       Subnet to be set.
    594   @param[in]  GatewayAddress   Gateway to be set.
    595 
    596   @retval EFI_SUCCESS     Set default If successful.
    597   @retval Others          Errors occur as indicated.
    598 
    599 **/
    600 EFI_STATUS
    601 Ip4Config2SetDefaultIf (
    602   IN IP4_CONFIG2_INSTANCE   *Instance,
    603   IN IP4_ADDR               StationAddress,
    604   IN IP4_ADDR               SubnetMask,
    605   IN IP4_ADDR               GatewayAddress
    606   )
    607 {
    608   EFI_STATUS                Status;
    609   IP4_SERVICE               *IpSb;
    610 
    611   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
    612 
    613   Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);
    614   if (EFI_ERROR (Status)) {
    615     return Status;
    616   }
    617 
    618   //
    619   // Create a route if there is a default router.
    620   //
    621   if (GatewayAddress != IP4_ALLZERO_ADDRESS) {
    622     Ip4AddRoute (
    623       IpSb->DefaultRouteTable,
    624       IP4_ALLZERO_ADDRESS,
    625       IP4_ALLZERO_ADDRESS,
    626       GatewayAddress
    627       );
    628   }
    629 
    630   return EFI_SUCCESS;
    631 }
    632 
    633 
    634 /**
    635   Release all the DHCP related resources.
    636 
    637   @param  Instance              The IP4 config2 instance.
    638 
    639   @return None
    640 
    641 **/
    642 VOID
    643 Ip4Config2CleanDhcp4 (
    644   IN IP4_CONFIG2_INSTANCE   *Instance
    645   )
    646 {
    647   IP4_SERVICE               *IpSb;
    648 
    649   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
    650 
    651   if (Instance->Dhcp4 != NULL) {
    652     Instance->Dhcp4->Stop (Instance->Dhcp4);
    653 
    654     gBS->CloseProtocol (
    655           Instance->Dhcp4Handle,
    656           &gEfiDhcp4ProtocolGuid,
    657           IpSb->Image,
    658           IpSb->Controller
    659           );
    660 
    661     Instance->Dhcp4 = NULL;
    662   }
    663 
    664   if (Instance->Dhcp4Handle != NULL) {
    665     NetLibDestroyServiceChild (
    666       IpSb->Controller,
    667       IpSb->Image,
    668       &gEfiDhcp4ServiceBindingProtocolGuid,
    669       Instance->Dhcp4Handle
    670       );
    671 
    672     Instance->Dhcp4Handle = NULL;
    673   }
    674 
    675   if (Instance->Dhcp4Event != NULL) {
    676     gBS->CloseEvent (Instance->Dhcp4Event);
    677     Instance->Dhcp4Event = NULL;
    678   }
    679 }
    680 
    681 /**
    682   This worker function sets the DNS server list for the EFI IPv4 network
    683   stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL
    684   manages. The DNS server addresses must be unicast IPv4 addresses.
    685 
    686   @param[in]     Instance        The pointer to the IP4 config2 instance data.
    687   @param[in]     DataSize        The size of the buffer pointed to by Data in bytes.
    688   @param[in]     Data            The data buffer to set, points to an array of
    689                                  EFI_IPv4_ADDRESS instances.
    690 
    691   @retval EFI_BAD_BUFFER_SIZE    The DataSize does not match the size of the type.
    692   @retval EFI_INVALID_PARAMETER  One or more fields in Data is invalid.
    693   @retval EFI_OUT_OF_RESOURCES   Failed to allocate resources to complete the operation.
    694   @retval EFI_ABORTED            The DNS server addresses to be set equal the current
    695                                  configuration.
    696   @retval EFI_SUCCESS            The specified configuration data for the EFI IPv4
    697                                  network stack was set.
    698 
    699 **/
    700 EFI_STATUS
    701 Ip4Config2SetDnsServerWorker (
    702   IN IP4_CONFIG2_INSTANCE    *Instance,
    703   IN UINTN                   DataSize,
    704   IN VOID                    *Data
    705   )
    706 {
    707   UINTN                 OldIndex;
    708   UINTN                 NewIndex;
    709   UINTN                 Index1;
    710   EFI_IPv4_ADDRESS      *OldDns;
    711   EFI_IPv4_ADDRESS      *NewDns;
    712   UINTN                 OldDnsCount;
    713   UINTN                 NewDnsCount;
    714   IP4_CONFIG2_DATA_ITEM *Item;
    715   BOOLEAN               OneAdded;
    716   VOID                  *Tmp;
    717   IP4_ADDR              DnsAddress;
    718 
    719   if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {
    720     return EFI_BAD_BUFFER_SIZE;
    721   }
    722 
    723   Item        = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
    724   NewDns      = (EFI_IPv4_ADDRESS *) Data;
    725   OldDns      = Item->Data.DnsServers;
    726   NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
    727   OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS);
    728   OneAdded    = FALSE;
    729 
    730   if (NewDnsCount != OldDnsCount) {
    731     Tmp = AllocatePool (DataSize);
    732     if (Tmp == NULL) {
    733       return EFI_OUT_OF_RESOURCES;
    734     }
    735   } else {
    736     Tmp = NULL;
    737   }
    738 
    739   for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {
    740     CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));
    741 
    742     if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) {
    743       //
    744       // The dns server address must be unicast.
    745       //
    746       FreePool (Tmp);
    747       return EFI_INVALID_PARAMETER;
    748     }
    749 
    750     for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {
    751       if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) {
    752         FreePool (Tmp);
    753         return EFI_INVALID_PARAMETER;
    754       }
    755     }
    756 
    757     if (OneAdded) {
    758       //
    759       // If any address in the new setting is not in the old settings, skip the
    760       // comparision below.
    761       //
    762       continue;
    763     }
    764 
    765     for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {
    766       if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {
    767         //
    768         // If found break out.
    769         //
    770         break;
    771       }
    772     }
    773 
    774     if (OldIndex == OldDnsCount) {
    775       OneAdded = TRUE;
    776     }
    777   }
    778 
    779   if (!OneAdded && (DataSize == Item->DataSize)) {
    780     //
    781     // No new item is added and the size is the same.
    782     //
    783     Item->Status = EFI_SUCCESS;
    784     return EFI_ABORTED;
    785   } else {
    786     if (Tmp != NULL) {
    787       if (Item->Data.Ptr != NULL) {
    788         FreePool (Item->Data.Ptr);
    789       }
    790       Item->Data.Ptr = Tmp;
    791     }
    792 
    793     CopyMem (Item->Data.Ptr, Data, DataSize);
    794     Item->DataSize = DataSize;
    795     Item->Status   = EFI_SUCCESS;
    796     return EFI_SUCCESS;
    797   }
    798 }
    799 
    800 
    801 
    802 /**
    803   Callback function when DHCP process finished. It will save the
    804   retrieved IP configure parameter from DHCP to the NVRam.
    805 
    806   @param  Event                  The callback event
    807   @param  Context                Opaque context to the callback
    808 
    809   @return None
    810 
    811 **/
    812 VOID
    813 EFIAPI
    814 Ip4Config2OnDhcp4Complete (
    815   IN EFI_EVENT              Event,
    816   IN VOID                   *Context
    817   )
    818 {
    819   IP4_CONFIG2_INSTANCE      *Instance;
    820   EFI_DHCP4_MODE_DATA       Dhcp4Mode;
    821   EFI_STATUS                Status;
    822   IP4_ADDR                  StationAddress;
    823   IP4_ADDR                  SubnetMask;
    824   IP4_ADDR                  GatewayAddress;
    825   UINT32                    Index;
    826   UINT32                    OptionCount;
    827   EFI_DHCP4_PACKET_OPTION   **OptionList;
    828 
    829   Instance = (IP4_CONFIG2_INSTANCE *) Context;
    830   ASSERT (Instance->Dhcp4 != NULL);
    831 
    832   //
    833   // Get the DHCP retrieved parameters
    834   //
    835   Status = Instance->Dhcp4->GetModeData (Instance->Dhcp4, &Dhcp4Mode);
    836 
    837   if (EFI_ERROR (Status)) {
    838     goto Exit;
    839   }
    840 
    841   if (Dhcp4Mode.State == Dhcp4Bound) {
    842     StationAddress = EFI_NTOHL (Dhcp4Mode.ClientAddress);
    843     SubnetMask = EFI_NTOHL (Dhcp4Mode.SubnetMask);
    844     GatewayAddress = EFI_NTOHL (Dhcp4Mode.RouterAddress);
    845 
    846     Status = Ip4Config2SetDefaultIf (Instance, StationAddress, SubnetMask, GatewayAddress);
    847     if (EFI_ERROR (Status)) {
    848       goto Exit;
    849     }
    850 
    851     //
    852     // Parse the ACK to get required DNS server information.
    853     //
    854     OptionCount = 0;
    855     OptionList  = NULL;
    856 
    857     Status      = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);
    858     if (Status != EFI_BUFFER_TOO_SMALL) {
    859       goto Exit;
    860     }
    861 
    862     OptionList = AllocateZeroPool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
    863     if (OptionList == NULL) {
    864       goto Exit;
    865     }
    866 
    867     Status = Instance->Dhcp4->Parse (Instance->Dhcp4, Dhcp4Mode.ReplyPacket, &OptionCount, OptionList);
    868     if (EFI_ERROR (Status)) {
    869       FreePool (OptionList);
    870       goto Exit;
    871     }
    872 
    873     for (Index = 0; Index < OptionCount; Index++) {
    874       //
    875       // Look for DNS Server opcode (6).
    876       //
    877       if (OptionList[Index]->OpCode == DHCP_TAG_DNS_SERVER) {
    878         if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
    879           break;
    880         }
    881 
    882         Ip4Config2SetDnsServerWorker (Instance, OptionList[Index]->Length, &OptionList[Index]->Data[0]);
    883         break;
    884       }
    885     }
    886 
    887     FreePool (OptionList);
    888 
    889     Instance->DhcpSuccess = TRUE;
    890   }
    891 
    892 Exit:
    893   Ip4Config2CleanDhcp4 (Instance);
    894   DispatchDpc ();
    895 }
    896 
    897 
    898 /**
    899   Start the DHCP configuration for this IP service instance.
    900   It will locates the EFI_IP4_CONFIG2_PROTOCOL, then start the
    901   DHCP configuration.
    902 
    903   @param[in]  Instance           The IP4 config2 instance to configure
    904 
    905   @retval EFI_SUCCESS            The auto configuration is successfull started
    906   @retval Others                 Failed to start auto configuration.
    907 
    908 **/
    909 EFI_STATUS
    910 Ip4StartAutoConfig (
    911   IN IP4_CONFIG2_INSTANCE   *Instance
    912   )
    913 {
    914   IP4_SERVICE                    *IpSb;
    915   EFI_DHCP4_PROTOCOL             *Dhcp4;
    916   EFI_DHCP4_MODE_DATA            Dhcp4Mode;
    917   EFI_DHCP4_PACKET_OPTION        *OptionList[1];
    918   IP4_CONFIG2_DHCP4_OPTION       ParaList;
    919   EFI_STATUS                     Status;
    920 
    921 
    922   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
    923 
    924   if (IpSb->State > IP4_SERVICE_UNSTARTED) {
    925     return EFI_SUCCESS;
    926   }
    927 
    928   //
    929   // A host must not invoke DHCP configuration if it is already
    930   // participating in the DHCP configuraiton process.
    931   //
    932   if (Instance->Dhcp4Handle != NULL) {
    933     return EFI_SUCCESS;
    934   }
    935 
    936   Status = NetLibCreateServiceChild (
    937              IpSb->Controller,
    938              IpSb->Image,
    939              &gEfiDhcp4ServiceBindingProtocolGuid,
    940              &Instance->Dhcp4Handle
    941              );
    942 
    943   if (Status == EFI_UNSUPPORTED) {
    944     //
    945     // No DHCPv4 Service Binding protocol, register a notify.
    946     //
    947     if (Instance->Dhcp4SbNotifyEvent == NULL) {
    948       Instance->Dhcp4SbNotifyEvent = EfiCreateProtocolNotifyEvent (
    949                                        &gEfiDhcp4ServiceBindingProtocolGuid,
    950                                        TPL_CALLBACK,
    951                                        Ip4Config2OnDhcp4SbInstalled,
    952                                        (VOID *) Instance,
    953                                        &Instance->Registration
    954                                        );
    955     }
    956   }
    957 
    958   if (EFI_ERROR (Status)) {
    959     return Status;
    960   }
    961 
    962   if (Instance->Dhcp4SbNotifyEvent != NULL) {
    963     gBS->CloseEvent (Instance->Dhcp4SbNotifyEvent);
    964   }
    965 
    966   Status = gBS->OpenProtocol (
    967                   Instance->Dhcp4Handle,
    968                   &gEfiDhcp4ProtocolGuid,
    969                   (VOID **) &Instance->Dhcp4,
    970                   IpSb->Image,
    971                   IpSb->Controller,
    972                   EFI_OPEN_PROTOCOL_BY_DRIVER
    973                   );
    974   ASSERT_EFI_ERROR (Status);
    975 
    976 
    977   //
    978   // Check the current DHCP status, if the DHCP process has
    979   // already finished, return now.
    980   //
    981   Dhcp4  = Instance->Dhcp4;
    982   Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);
    983 
    984   if (Dhcp4Mode.State == Dhcp4Bound) {
    985     Ip4Config2OnDhcp4Complete (NULL, Instance);
    986     return EFI_SUCCESS;
    987 
    988   }
    989 
    990   //
    991   // Try to start the DHCP process. Use most of the current
    992   // DHCP configuration to avoid problems if some DHCP client
    993   // yields the control of this DHCP service to us.
    994   //
    995   ParaList.Head.OpCode             = DHCP_TAG_PARA_LIST;
    996   ParaList.Head.Length             = 3;
    997   ParaList.Head.Data[0]            = DHCP_TAG_NETMASK;
    998   ParaList.Route                   = DHCP_TAG_ROUTER;
    999   ParaList.Dns                     = DHCP_TAG_DNS_SERVER;
   1000   OptionList[0]                    = &ParaList.Head;
   1001   Dhcp4Mode.ConfigData.OptionCount = 1;
   1002   Dhcp4Mode.ConfigData.OptionList  = OptionList;
   1003 
   1004   Status = Dhcp4->Configure (Dhcp4, &Dhcp4Mode.ConfigData);
   1005 
   1006   if (EFI_ERROR (Status)) {
   1007     return Status;
   1008   }
   1009 
   1010   //
   1011   // Start the DHCP process
   1012   //
   1013   Status = gBS->CreateEvent (
   1014                   EVT_NOTIFY_SIGNAL,
   1015                   TPL_CALLBACK,
   1016                   Ip4Config2OnDhcp4Complete,
   1017                   Instance,
   1018                   &Instance->Dhcp4Event
   1019                   );
   1020 
   1021   if (EFI_ERROR (Status)) {
   1022     return Status;
   1023   }
   1024 
   1025   Status = Dhcp4->Start (Dhcp4, Instance->Dhcp4Event);
   1026 
   1027   if (EFI_ERROR (Status)) {
   1028     return Status;
   1029   }
   1030 
   1031   IpSb->State     = IP4_SERVICE_STARTED;
   1032   DispatchDpc ();
   1033   return EFI_SUCCESS;
   1034 
   1035 }
   1036 
   1037 
   1038 
   1039 /**
   1040   The work function is to get the interface information of the communication
   1041   device this IP4_CONFIG2_INSTANCE manages.
   1042 
   1043   @param[in]      Instance Pointer to the IP4 config2 instance data.
   1044   @param[in, out] DataSize On input, in bytes, the size of Data. On output, in
   1045                            bytes, the size of buffer required to store the specified
   1046                            configuration data.
   1047   @param[in]      Data     The data buffer in which the configuration data is returned.
   1048                            Ignored if DataSize is ZERO.
   1049 
   1050   @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified
   1051                                configuration data, and the required size is
   1052                                returned in DataSize.
   1053   @retval EFI_SUCCESS          The specified configuration data was obtained.
   1054 
   1055 **/
   1056 EFI_STATUS
   1057 Ip4Config2GetIfInfo (
   1058   IN IP4_CONFIG2_INSTANCE *Instance,
   1059   IN OUT UINTN            *DataSize,
   1060   IN VOID                 *Data      OPTIONAL
   1061   )
   1062 {
   1063 
   1064   IP4_SERVICE                    *IpSb;
   1065   UINTN                          Length;
   1066   IP4_CONFIG2_DATA_ITEM          *Item;
   1067   EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;
   1068   IP4_ADDR                       Address;
   1069 
   1070   IpSb   = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1071   Length = sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO);
   1072 
   1073   if (IpSb->DefaultRouteTable != NULL) {
   1074     Length += IpSb->DefaultRouteTable->TotalNum * sizeof (EFI_IP4_ROUTE_TABLE);
   1075   }
   1076 
   1077   if (*DataSize < Length) {
   1078     *DataSize = Length;
   1079     return EFI_BUFFER_TOO_SMALL;
   1080   }
   1081 
   1082   //
   1083   // Copy the fixed size part of the interface info.
   1084   //
   1085   Item = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];
   1086   IfInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *) Data;
   1087   CopyMem (IfInfo, Item->Data.Ptr, sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));
   1088 
   1089   //
   1090   // Update the address info.
   1091   //
   1092   if (IpSb->DefaultInterface != NULL) {
   1093     Address = HTONL (IpSb->DefaultInterface->Ip);
   1094     CopyMem (&IfInfo->StationAddress, &Address, sizeof (EFI_IPv4_ADDRESS));
   1095     Address = HTONL (IpSb->DefaultInterface->SubnetMask);
   1096     CopyMem (&IfInfo->SubnetMask, &Address, sizeof (EFI_IPv4_ADDRESS));
   1097   }
   1098 
   1099   if (IpSb->DefaultRouteTable != NULL) {
   1100     IfInfo->RouteTableSize = IpSb->DefaultRouteTable->TotalNum;
   1101     IfInfo->RouteTable   = (EFI_IP4_ROUTE_TABLE *) ((UINT8 *) Data + sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));
   1102 
   1103     Ip4Config2BuildDefaultRouteTable (IpSb, IfInfo->RouteTable);
   1104   }
   1105 
   1106   return EFI_SUCCESS;
   1107 }
   1108 
   1109 /**
   1110   The work function is to set the general configuration policy for the EFI IPv4 network
   1111   stack that is running on the communication device managed by this IP4_CONFIG2_INSTANCE.
   1112   The policy will affect other configuration settings.
   1113 
   1114   @param[in]     Instance Pointer to the IP4 config2 instance data.
   1115   @param[in]     DataSize Size of the buffer pointed to by Data in bytes.
   1116   @param[in]     Data     The data buffer to set.
   1117 
   1118   @retval EFI_INVALID_PARAMETER The to be set policy is invalid.
   1119   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
   1120   @retval EFI_ABORTED           The new policy equals the current policy.
   1121   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
   1122                                 network stack was set.
   1123 
   1124 **/
   1125 EFI_STATUS
   1126 Ip4Config2SetPolicy (
   1127   IN IP4_CONFIG2_INSTANCE *Instance,
   1128   IN UINTN                DataSize,
   1129   IN VOID                 *Data
   1130   )
   1131 {
   1132   EFI_IP4_CONFIG2_POLICY NewPolicy;
   1133   IP4_CONFIG2_DATA_ITEM  *DataItem;
   1134   IP4_SERVICE            *IpSb;
   1135 
   1136   if (DataSize != sizeof (EFI_IP4_CONFIG2_POLICY)) {
   1137     return EFI_BAD_BUFFER_SIZE;
   1138   }
   1139 
   1140   NewPolicy = *((EFI_IP4_CONFIG2_POLICY *) Data);
   1141 
   1142   if (NewPolicy >= Ip4Config2PolicyMax) {
   1143     return EFI_INVALID_PARAMETER;
   1144   }
   1145 
   1146   if (NewPolicy == Instance->Policy) {
   1147      return EFI_ABORTED;
   1148   } else {
   1149     if (NewPolicy == Ip4Config2PolicyDhcp) {
   1150       //
   1151       // The policy is changed from static to dhcp:
   1152       // Clean the ManualAddress, Gateway and DnsServers, shrink the variable
   1153       // data size, and fire up all the related events.
   1154       //
   1155       DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
   1156       if (DataItem->Data.Ptr != NULL) {
   1157         FreePool (DataItem->Data.Ptr);
   1158       }
   1159       DataItem->Data.Ptr = NULL;
   1160       DataItem->DataSize = 0;
   1161       DataItem->Status   = EFI_NOT_FOUND;
   1162       NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
   1163 
   1164       DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];
   1165       if (DataItem->Data.Ptr != NULL) {
   1166         FreePool (DataItem->Data.Ptr);
   1167       }
   1168       DataItem->Data.Ptr = NULL;
   1169       DataItem->DataSize = 0;
   1170       DataItem->Status   = EFI_NOT_FOUND;
   1171       NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
   1172 
   1173       DataItem           = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
   1174       if (DataItem->Data.Ptr != NULL) {
   1175         FreePool (DataItem->Data.Ptr);
   1176       }
   1177       DataItem->Data.Ptr = NULL;
   1178       DataItem->DataSize = 0;
   1179       DataItem->Status   = EFI_NOT_FOUND;
   1180       NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);
   1181     } else {
   1182       //
   1183       // The policy is changed from dhcp to static. Stop the DHCPv4 process
   1184       // and destroy the DHCPv4 child.
   1185       //
   1186       if (Instance->Dhcp4Handle != NULL) {
   1187         Ip4Config2DestroyDhcp4 (Instance);
   1188       }
   1189 
   1190       //
   1191       // Close the event.
   1192       //
   1193       if (Instance->Dhcp4Event != NULL) {
   1194         gBS->CloseEvent (Instance->Dhcp4Event);
   1195       }
   1196     }
   1197   }
   1198 
   1199   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1200   Ip4Config2OnPolicyChanged (IpSb, NewPolicy);
   1201 
   1202   Instance->Policy = NewPolicy;
   1203 
   1204   return EFI_SUCCESS;
   1205 }
   1206 
   1207 /**
   1208   The work function is to set the station addresses manually for the EFI IPv4
   1209   network stack. It is only configurable when the policy is Ip4Config2PolicyStatic.
   1210 
   1211   @param[in]     Instance Pointer to the IP4 config2 instance data.
   1212   @param[in]     DataSize Size of the buffer pointed to by Data in bytes.
   1213   @param[in]     Data     The data buffer to set.
   1214 
   1215   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
   1216   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
   1217                                 under the current policy.
   1218   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
   1219   @retval EFI_OUT_OF_RESOURCES  Fail to allocate resource to complete the operation.
   1220   @retval EFI_NOT_READY         An asynchrous process is invoked to set the specified
   1221                                 configuration data, and the process is not finished.
   1222   @retval EFI_ABORTED           The manual addresses to be set equal current
   1223                                 configuration.
   1224   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
   1225                                 network stack was set.
   1226 
   1227 **/
   1228 EFI_STATUS
   1229 Ip4Config2SetMaunualAddress (
   1230   IN IP4_CONFIG2_INSTANCE *Instance,
   1231   IN UINTN                DataSize,
   1232   IN VOID                 *Data
   1233   )
   1234 {
   1235   EFI_IP4_CONFIG2_MANUAL_ADDRESS NewAddress;
   1236   IP4_CONFIG2_DATA_ITEM          *DataItem;
   1237   EFI_STATUS                     Status;
   1238   IP4_ADDR                       StationAddress;
   1239   IP4_ADDR                       SubnetMask;
   1240   VOID                           *Ptr;
   1241   IP4_SERVICE                    *IpSb;
   1242 
   1243   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1244 
   1245   ASSERT (Instance->DataItem[Ip4Config2DataTypeManualAddress].Status != EFI_NOT_READY);
   1246 
   1247   if (((DataSize % sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {
   1248     return EFI_BAD_BUFFER_SIZE;
   1249   }
   1250 
   1251   if (Instance->Policy != Ip4Config2PolicyStatic) {
   1252     return EFI_WRITE_PROTECTED;
   1253   }
   1254 
   1255   NewAddress = *((EFI_IP4_CONFIG2_MANUAL_ADDRESS *) Data);
   1256 
   1257   //
   1258   // Store the new data, and init the DataItem status to EFI_NOT_READY because
   1259   // we may have an asynchronous configuration process.
   1260   //
   1261   Ptr = AllocateCopyPool (DataSize, Data);
   1262   if (Ptr == NULL) {
   1263     return EFI_OUT_OF_RESOURCES;
   1264   }
   1265 
   1266   DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
   1267   if (DataItem->Data.Ptr != NULL) {
   1268     FreePool (DataItem->Data.Ptr);
   1269   }
   1270 
   1271   DataItem->Data.Ptr = Ptr;
   1272   DataItem->DataSize = DataSize;
   1273   DataItem->Status   = EFI_NOT_READY;
   1274 
   1275   StationAddress = EFI_NTOHL (NewAddress.Address);
   1276   SubnetMask = EFI_NTOHL (NewAddress.SubnetMask);
   1277 
   1278   IpSb->Reconfig = TRUE;
   1279   Status = Ip4Config2SetDefaultAddr (IpSb, StationAddress, SubnetMask);
   1280   if (EFI_ERROR (Status)) {
   1281     goto ON_EXIT;
   1282   }
   1283 
   1284   DataItem->Status = EFI_SUCCESS;
   1285 
   1286 ON_EXIT:
   1287   if (EFI_ERROR (DataItem->Status)) {
   1288     if (Ptr != NULL) {
   1289       FreePool (Ptr);
   1290     }
   1291     DataItem->Data.Ptr = NULL;
   1292   }
   1293 
   1294   return EFI_SUCCESS;
   1295 }
   1296 
   1297 /**
   1298   The work function is to set the gateway addresses manually for the EFI IPv4
   1299   network stack that is running on the communication device that this EFI IPv4
   1300   Configuration Protocol manages. It is not configurable when the policy is
   1301   Ip4Config2PolicyDhcp. The gateway addresses must be unicast IPv4 addresses.
   1302 
   1303   @param[in]     Instance The pointer to the IP4 config2 instance data.
   1304   @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
   1305   @param[in]     Data     The data buffer to set. This points to an array of
   1306                           EFI_IPv6_ADDRESS instances.
   1307 
   1308   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
   1309   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
   1310                                 under the current policy.
   1311   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
   1312   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resource to complete the operation.
   1313   @retval EFI_ABORTED           The manual gateway addresses to be set equal the
   1314                                 current configuration.
   1315   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
   1316                                 network stack was set.
   1317 
   1318 **/
   1319 EFI_STATUS
   1320 Ip4Config2SetGateway (
   1321   IN IP4_CONFIG2_INSTANCE *Instance,
   1322   IN UINTN                DataSize,
   1323   IN VOID                 *Data
   1324   )
   1325 {
   1326   IP4_SERVICE                    *IpSb;
   1327   IP4_CONFIG2_DATA_ITEM          *DataItem;
   1328   IP4_ADDR                       Gateway;
   1329 
   1330   UINTN                 Index1;
   1331   UINTN                 Index2;
   1332   EFI_IPv4_ADDRESS      *OldGateway;
   1333   EFI_IPv4_ADDRESS      *NewGateway;
   1334   UINTN                 OldGatewayCount;
   1335   UINTN                 NewGatewayCount;
   1336   BOOLEAN               OneRemoved;
   1337   BOOLEAN               OneAdded;
   1338   VOID                  *Tmp;
   1339 
   1340   if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {
   1341     return EFI_BAD_BUFFER_SIZE;
   1342   }
   1343 
   1344   if (Instance->Policy != Ip4Config2PolicyStatic) {
   1345     return EFI_WRITE_PROTECTED;
   1346   }
   1347 
   1348 
   1349   NewGateway      = (EFI_IPv4_ADDRESS *) Data;
   1350   NewGatewayCount = DataSize / sizeof (EFI_IPv4_ADDRESS);
   1351   for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
   1352     CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));
   1353 
   1354     if (!NetIp4IsUnicast (NTOHL (Gateway), 0)) {
   1355 
   1356       return EFI_INVALID_PARAMETER;
   1357     }
   1358 
   1359     for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {
   1360       if (EFI_IP4_EQUAL (NewGateway + Index1, NewGateway + Index2)) {
   1361         return EFI_INVALID_PARAMETER;
   1362       }
   1363     }
   1364   }
   1365 
   1366   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1367   DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];
   1368   OldGateway      = DataItem->Data.Gateway;
   1369   OldGatewayCount = DataItem->DataSize / sizeof (EFI_IPv4_ADDRESS);
   1370   OneRemoved      = FALSE;
   1371   OneAdded        = FALSE;
   1372 
   1373   if (NewGatewayCount != OldGatewayCount) {
   1374     Tmp = AllocatePool (DataSize);
   1375     if (Tmp == NULL) {
   1376       return EFI_OUT_OF_RESOURCES;
   1377     }
   1378   } else {
   1379     Tmp = NULL;
   1380   }
   1381 
   1382   for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {
   1383     //
   1384     // Remove this route entry.
   1385     //
   1386     CopyMem (&Gateway, OldGateway + Index1, sizeof (IP4_ADDR));
   1387     Ip4DelRoute (
   1388       IpSb->DefaultRouteTable,
   1389       IP4_ALLZERO_ADDRESS,
   1390       IP4_ALLZERO_ADDRESS,
   1391       NTOHL (Gateway)
   1392       );
   1393     OneRemoved = TRUE;
   1394 
   1395   }
   1396 
   1397   for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {
   1398     CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));
   1399     Ip4AddRoute (
   1400       IpSb->DefaultRouteTable,
   1401       IP4_ALLZERO_ADDRESS,
   1402       IP4_ALLZERO_ADDRESS,
   1403       NTOHL (Gateway)
   1404       );
   1405 
   1406     OneAdded = TRUE;
   1407   }
   1408 
   1409 
   1410   if (!OneRemoved && !OneAdded) {
   1411     DataItem->Status = EFI_SUCCESS;
   1412     return EFI_ABORTED;
   1413   } else {
   1414 
   1415     if (Tmp != NULL) {
   1416       if (DataItem->Data.Ptr != NULL) {
   1417         FreePool (DataItem->Data.Ptr);
   1418       }
   1419       DataItem->Data.Ptr = Tmp;
   1420     }
   1421 
   1422     CopyMem (DataItem->Data.Ptr, Data, DataSize);
   1423     DataItem->DataSize = DataSize;
   1424     DataItem->Status   = EFI_SUCCESS;
   1425     return EFI_SUCCESS;
   1426   }
   1427 
   1428 }
   1429 
   1430 /**
   1431   The work function is to set the DNS server list for the EFI IPv4 network
   1432   stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL
   1433   manages. It is not configurable when the policy is Ip4Config2PolicyDhcp.
   1434   The DNS server addresses must be unicast IPv4 addresses.
   1435 
   1436   @param[in]     Instance The pointer to the IP4 config2 instance data.
   1437   @param[in]     DataSize The size of the buffer pointed to by Data in bytes.
   1438   @param[in]     Data     The data buffer to set, points to an array of
   1439                           EFI_IPv4_ADDRESS instances.
   1440 
   1441   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type.
   1442   @retval EFI_WRITE_PROTECTED   The specified configuration data cannot be set
   1443                                 under the current policy.
   1444   @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.
   1445   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
   1446   @retval EFI_ABORTED           The DNS server addresses to be set equal the current
   1447                                 configuration.
   1448   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv4
   1449                                 network stack was set.
   1450 
   1451 **/
   1452 EFI_STATUS
   1453 Ip4Config2SetDnsServer (
   1454   IN IP4_CONFIG2_INSTANCE *Instance,
   1455   IN UINTN                DataSize,
   1456   IN VOID                 *Data
   1457   )
   1458 {
   1459   if (Instance->Policy != Ip4Config2PolicyStatic) {
   1460     return EFI_WRITE_PROTECTED;
   1461   }
   1462 
   1463   return Ip4Config2SetDnsServerWorker (Instance, DataSize, Data);
   1464 }
   1465 
   1466 /**
   1467   Generate the operational state of the interface this IP4 config2 instance manages
   1468   and output in EFI_IP4_CONFIG2_INTERFACE_INFO.
   1469 
   1470   @param[in]      IpSb     The pointer to the IP4 service binding instance.
   1471   @param[out]     IfInfo   The pointer to the IP4 config2 interface information structure.
   1472 
   1473 **/
   1474 VOID
   1475 Ip4Config2InitIfInfo (
   1476   IN  IP4_SERVICE                    *IpSb,
   1477   OUT EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo
   1478   )
   1479 {
   1480   IfInfo->Name[0] = L'e';
   1481   IfInfo->Name[1] = L't';
   1482   IfInfo->Name[2] = L'h';
   1483   IfInfo->Name[3] = (CHAR16) (L'0' + IpSb->Ip4Config2Instance.IfIndex);
   1484   IfInfo->Name[4] = 0;
   1485 
   1486   IfInfo->IfType        = IpSb->SnpMode.IfType;
   1487   IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;
   1488   CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);
   1489 }
   1490 
   1491 /**
   1492   The event handle routine when DHCPv4 process is finished or is updated.
   1493 
   1494   @param[in]     Event         Not used.
   1495   @param[in]     Context       The pointer to the IP4 configuration instance data.
   1496 
   1497 **/
   1498 VOID
   1499 EFIAPI
   1500 Ip4Config2OnDhcp4Event (
   1501   IN EFI_EVENT  Event,
   1502   IN VOID       *Context
   1503   )
   1504 {
   1505   return ;
   1506 }
   1507 
   1508 
   1509 /**
   1510   Set the configuration for the EFI IPv4 network stack running on the communication
   1511   device this EFI_IP4_CONFIG2_PROTOCOL instance manages.
   1512 
   1513   This function is used to set the configuration data of type DataType for the EFI
   1514   IPv4 network stack that is running on the communication device that this EFI IPv4
   1515   Configuration Protocol instance manages.
   1516 
   1517   DataSize is used to calculate the count of structure instances in the Data for
   1518   a DataType in which multiple structure instances are allowed.
   1519 
   1520   This function is always non-blocking. When setting some type of configuration data,
   1521   an asynchronous process is invoked to check the correctness of the data, such as
   1522   performing Duplicate Address Detection on the manually set local IPv4 addresses.
   1523   EFI_NOT_READY is returned immediately to indicate that such an asynchronous process
   1524   is invoked, and the process is not finished yet. The caller wanting to get the result
   1525   of the asynchronous process is required to call RegisterDataNotify() to register an
   1526   event on the specified configuration data. Once the event is signaled, the caller
   1527   can call GetData() to obtain the configuration data and know the result.
   1528   For other types of configuration data that do not require an asynchronous configuration
   1529   process, the result of the operation is immediately returned.
   1530 
   1531   @param[in]     This           The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
   1532   @param[in]     DataType       The type of data to set.
   1533   @param[in]     DataSize       Size of the buffer pointed to by Data in bytes.
   1534   @param[in]     Data           The data buffer to set. The type of the data buffer is
   1535                                 associated with the DataType.
   1536 
   1537   @retval EFI_SUCCESS           The specified configuration data for the EFI IPv6
   1538                                 network stack was set successfully.
   1539   @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:
   1540                                 - This is NULL.
   1541                                 - Data is NULL.
   1542                                 - One or more fields in Data do not match the requirement of the
   1543                                   data type indicated by DataType.
   1544   @retval EFI_WRITE_PROTECTED   The specified configuration data is read-only or the specified
   1545                                 configuration data cannot be set under the current policy.
   1546   @retval EFI_ACCESS_DENIED     Another set operation on the specified configuration
   1547                                 data is already in process.
   1548   @retval EFI_NOT_READY         An asynchronous process was invoked to set the specified
   1549                                 configuration data, and the process is not finished yet.
   1550   @retval EFI_BAD_BUFFER_SIZE   The DataSize does not match the size of the type
   1551                                 indicated by DataType.
   1552   @retval EFI_UNSUPPORTED       This DataType is not supported.
   1553   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1554   @retval EFI_DEVICE_ERROR      An unexpected system error or network error occurred.
   1555 
   1556 **/
   1557 EFI_STATUS
   1558 EFIAPI
   1559 EfiIp4Config2SetData (
   1560   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
   1561   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
   1562   IN UINTN                      DataSize,
   1563   IN VOID                       *Data
   1564   )
   1565 {
   1566   EFI_TPL              OldTpl;
   1567   EFI_STATUS           Status;
   1568   IP4_CONFIG2_INSTANCE *Instance;
   1569   IP4_SERVICE          *IpSb;
   1570 
   1571   if ((This == NULL) || (Data == NULL)) {
   1572     return EFI_INVALID_PARAMETER;
   1573   }
   1574 
   1575   if (DataType >= Ip4Config2DataTypeMaximum) {
   1576     return EFI_UNSUPPORTED;
   1577   }
   1578 
   1579   Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
   1580   IpSb     = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1581   NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);
   1582 
   1583 
   1584   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1585 
   1586   Status = Instance->DataItem[DataType].Status;
   1587   if (Status != EFI_NOT_READY) {
   1588 
   1589     if (Instance->DataItem[DataType].SetData == NULL) {
   1590       //
   1591       // This type of data is readonly.
   1592       //
   1593       Status = EFI_WRITE_PROTECTED;
   1594     } else {
   1595 
   1596       Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);
   1597       if (!EFI_ERROR (Status)) {
   1598         //
   1599         // Fire up the events registered with this type of data.
   1600         //
   1601         NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);
   1602         Ip4Config2WriteConfigData (IpSb->MacString, Instance);
   1603       } else if (Status == EFI_ABORTED) {
   1604         //
   1605         // The SetData is aborted because the data to set is the same with
   1606         // the one maintained.
   1607         //
   1608         Status = EFI_SUCCESS;
   1609         NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);
   1610       }
   1611     }
   1612   } else {
   1613     //
   1614     // Another asynchornous process is on the way.
   1615     //
   1616     Status = EFI_ACCESS_DENIED;
   1617   }
   1618 
   1619   gBS->RestoreTPL (OldTpl);
   1620 
   1621   return Status;
   1622 }
   1623 
   1624 /**
   1625   Get the configuration data for the EFI IPv4 network stack running on the communication
   1626   device that this EFI_IP4_CONFIG2_PROTOCOL instance manages.
   1627 
   1628   This function returns the configuration data of type DataType for the EFI IPv4 network
   1629   stack running on the communication device that this EFI IPv4 Configuration Protocol instance
   1630   manages.
   1631 
   1632   The caller is responsible for allocating the buffer used to return the specified
   1633   configuration data. The required size will be returned to the caller if the size of
   1634   the buffer is too small.
   1635 
   1636   EFI_NOT_READY is returned if the specified configuration data is not ready due to an
   1637   asynchronous configuration process already in progress. The caller can call RegisterDataNotify()
   1638   to register an event on the specified configuration data. Once the asynchronous configuration
   1639   process is finished, the event will be signaled, and a subsequent GetData() call will return
   1640   the specified configuration data.
   1641 
   1642   @param[in]      This           Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
   1643   @param[in]      DataType       The type of data to get.
   1644   @param[in, out] DataSize       On input, in bytes, the size of Data. On output, in bytes, the
   1645                                  size of buffer required to store the specified configuration data.
   1646   @param[in]     Data            The data buffer in which the configuration data is returned. The
   1647                                  type of the data buffer is associated with the DataType.
   1648                                  This is an optional parameter that may be NULL.
   1649 
   1650   @retval EFI_SUCCESS           The specified configuration data was obtained successfully.
   1651   @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:
   1652                                 - This is NULL.
   1653                                 - DataSize is NULL.
   1654                                 - Data is NULL if *DataSize is not zero.
   1655   @retval EFI_BUFFER_TOO_SMALL  The size of Data is too small for the specified configuration data,
   1656                                 and the required size is returned in DataSize.
   1657   @retval EFI_NOT_READY         The specified configuration data is not ready due to an
   1658                                 asynchronous configuration process already in progress.
   1659   @retval EFI_NOT_FOUND         The specified configuration data is not found.
   1660 
   1661 **/
   1662 EFI_STATUS
   1663 EFIAPI
   1664 EfiIp4Config2GetData (
   1665   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
   1666   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
   1667   IN OUT UINTN                  *DataSize,
   1668   IN VOID                       *Data   OPTIONAL
   1669   )
   1670 {
   1671   EFI_TPL               OldTpl;
   1672   EFI_STATUS            Status;
   1673   IP4_CONFIG2_INSTANCE  *Instance;
   1674   IP4_CONFIG2_DATA_ITEM *DataItem;
   1675 
   1676   if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {
   1677     return EFI_INVALID_PARAMETER;
   1678   }
   1679 
   1680   if (DataType >= Ip4Config2DataTypeMaximum) {
   1681     return EFI_NOT_FOUND;
   1682   }
   1683 
   1684   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1685 
   1686   Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
   1687   DataItem = &Instance->DataItem[DataType];
   1688 
   1689   Status   = Instance->DataItem[DataType].Status;
   1690   if (!EFI_ERROR (Status)) {
   1691 
   1692     if (DataItem->GetData != NULL) {
   1693 
   1694       Status = DataItem->GetData (Instance, DataSize, Data);
   1695     } else if (*DataSize < Instance->DataItem[DataType].DataSize) {
   1696       //
   1697       // Update the buffer length.
   1698       //
   1699       *DataSize = Instance->DataItem[DataType].DataSize;
   1700       Status    = EFI_BUFFER_TOO_SMALL;
   1701     } else {
   1702 
   1703       *DataSize = Instance->DataItem[DataType].DataSize;
   1704       CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);
   1705     }
   1706   }
   1707 
   1708   gBS->RestoreTPL (OldTpl);
   1709 
   1710   return Status;
   1711 }
   1712 
   1713 /**
   1714   Register an event that is signaled whenever a configuration process on the specified
   1715   configuration data is done.
   1716 
   1717   This function registers an event that is to be signaled whenever a configuration
   1718   process on the specified configuration data is performed. An event can be registered
   1719   for a different DataType simultaneously. The caller is responsible for determining
   1720   which type of configuration data causes the signaling of the event in such an event.
   1721 
   1722   @param[in]     This           Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
   1723   @param[in]     DataType       The type of data to unregister the event for.
   1724   @param[in]     Event          The event to register.
   1725 
   1726   @retval EFI_SUCCESS           The notification event for the specified configuration data is
   1727                                 registered.
   1728   @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.
   1729   @retval EFI_UNSUPPORTED       The configuration data type specified by DataType is not
   1730                                 supported.
   1731   @retval EFI_OUT_OF_RESOURCES  Required system resources could not be allocated.
   1732   @retval EFI_ACCESS_DENIED     The Event is already registered for the DataType.
   1733 
   1734 **/
   1735 EFI_STATUS
   1736 EFIAPI
   1737 EfiIp4Config2RegisterDataNotify (
   1738   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
   1739   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
   1740   IN EFI_EVENT                  Event
   1741   )
   1742 {
   1743   EFI_TPL              OldTpl;
   1744   EFI_STATUS           Status;
   1745   IP4_CONFIG2_INSTANCE *Instance;
   1746   NET_MAP              *EventMap;
   1747   NET_MAP_ITEM         *Item;
   1748 
   1749   if ((This == NULL) || (Event == NULL)) {
   1750     return EFI_INVALID_PARAMETER;
   1751   }
   1752 
   1753   if (DataType >= Ip4Config2DataTypeMaximum) {
   1754     return EFI_UNSUPPORTED;
   1755   }
   1756 
   1757   OldTpl    = gBS->RaiseTPL (TPL_CALLBACK);
   1758 
   1759   Instance  = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
   1760   EventMap  = &Instance->DataItem[DataType].EventMap;
   1761 
   1762   //
   1763   // Check whether this event is already registered for this DataType.
   1764   //
   1765   Item = NetMapFindKey (EventMap, Event);
   1766   if (Item == NULL) {
   1767 
   1768     Status = NetMapInsertTail (EventMap, Event, NULL);
   1769 
   1770     if (EFI_ERROR (Status)) {
   1771 
   1772       Status = EFI_OUT_OF_RESOURCES;
   1773     }
   1774 
   1775   } else {
   1776 
   1777     Status = EFI_ACCESS_DENIED;
   1778   }
   1779 
   1780   gBS->RestoreTPL (OldTpl);
   1781 
   1782   return Status;
   1783 }
   1784 
   1785 /**
   1786   Remove a previously registered event for the specified configuration data.
   1787 
   1788   @param  This                   The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.
   1789   @param  DataType               The type of data to remove from the previously
   1790                                  registered event.
   1791   @param  Event                  The event to be unregistered.
   1792 
   1793   @retval EFI_SUCCESS            The event registered for the specified
   1794                                  configuration data was removed.
   1795   @retval EFI_INVALID_PARAMETER  This is NULL or Event is NULL.
   1796   @retval EFI_NOT_FOUND          The Event has not been registered for the
   1797                                  specified DataType.
   1798 
   1799 **/
   1800 EFI_STATUS
   1801 EFIAPI
   1802 EfiIp4Config2UnregisterDataNotify (
   1803   IN EFI_IP4_CONFIG2_PROTOCOL   *This,
   1804   IN EFI_IP4_CONFIG2_DATA_TYPE  DataType,
   1805   IN EFI_EVENT                  Event
   1806   )
   1807 {
   1808   EFI_TPL              OldTpl;
   1809   EFI_STATUS           Status;
   1810   IP4_CONFIG2_INSTANCE *Instance;
   1811   NET_MAP_ITEM         *Item;
   1812 
   1813   if ((This == NULL) || (Event == NULL)) {
   1814     return EFI_INVALID_PARAMETER;
   1815   }
   1816 
   1817   if (DataType >= Ip4Config2DataTypeMaximum) {
   1818     return EFI_NOT_FOUND;
   1819   }
   1820 
   1821   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
   1822 
   1823   Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);
   1824 
   1825   Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);
   1826   if (Item != NULL) {
   1827 
   1828     NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);
   1829     Status = EFI_SUCCESS;
   1830   } else {
   1831 
   1832     Status = EFI_NOT_FOUND;
   1833   }
   1834 
   1835   gBS->RestoreTPL (OldTpl);
   1836 
   1837   return Status;
   1838 }
   1839 
   1840 /**
   1841   Initialize an IP4_CONFIG2_INSTANCE.
   1842 
   1843   @param[out]    Instance       The buffer of IP4_CONFIG2_INSTANCE to be initialized.
   1844 
   1845   @retval EFI_OUT_OF_RESOURCES  Failed to allocate resources to complete the operation.
   1846   @retval EFI_SUCCESS           The IP4_CONFIG2_INSTANCE initialized successfully.
   1847 
   1848 **/
   1849 EFI_STATUS
   1850 Ip4Config2InitInstance (
   1851   OUT IP4_CONFIG2_INSTANCE  *Instance
   1852   )
   1853 {
   1854   IP4_SERVICE           *IpSb;
   1855   IP4_CONFIG2_INSTANCE  *TmpInstance;
   1856   LIST_ENTRY            *Entry;
   1857   EFI_STATUS            Status;
   1858   UINTN                 Index;
   1859   UINT16                IfIndex;
   1860   IP4_CONFIG2_DATA_ITEM *DataItem;
   1861 
   1862 
   1863   IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);
   1864 
   1865   Instance->Signature = IP4_CONFIG2_INSTANCE_SIGNATURE;
   1866 
   1867 
   1868   //
   1869   // Determine the index of this interface.
   1870   //
   1871   IfIndex = 0;
   1872   NET_LIST_FOR_EACH (Entry, &mIp4Config2InstanceList) {
   1873     TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_CONFIG2_INSTANCE, Link, IP4_CONFIG2_INSTANCE_SIGNATURE);
   1874 
   1875     if (TmpInstance->IfIndex > IfIndex) {
   1876       //
   1877       // There is a sequence hole because some interface is down.
   1878       //
   1879       break;
   1880     }
   1881 
   1882     IfIndex++;
   1883   }
   1884 
   1885   Instance->IfIndex = IfIndex;
   1886   NetListInsertBefore (Entry, &Instance->Link);
   1887 
   1888   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
   1889     //
   1890     // Initialize the event map for each data item.
   1891     //
   1892     NetMapInit (&Instance->DataItem[Index].EventMap);
   1893   }
   1894 
   1895 
   1896   //
   1897   // Initialize each data type: associate storage and set data size for the
   1898   // fixed size data types, hook the SetData function, set the data attribute.
   1899   //
   1900   DataItem           = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];
   1901   DataItem->GetData  = Ip4Config2GetIfInfo;
   1902   DataItem->Data.Ptr = &Instance->InterfaceInfo;
   1903   DataItem->DataSize = sizeof (Instance->InterfaceInfo);
   1904   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);
   1905   Ip4Config2InitIfInfo (IpSb, &Instance->InterfaceInfo);
   1906 
   1907   DataItem           = &Instance->DataItem[Ip4Config2DataTypePolicy];
   1908   DataItem->SetData  = Ip4Config2SetPolicy;
   1909   DataItem->Data.Ptr = &Instance->Policy;
   1910   DataItem->DataSize = sizeof (Instance->Policy);
   1911   Instance->Policy   = Ip4Config2PolicyDhcp;
   1912   SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);
   1913 
   1914   DataItem           = &Instance->DataItem[Ip4Config2DataTypeManualAddress];
   1915   DataItem->SetData  = Ip4Config2SetMaunualAddress;
   1916   DataItem->Status   = EFI_NOT_FOUND;
   1917 
   1918   DataItem           = &Instance->DataItem[Ip4Config2DataTypeGateway];
   1919   DataItem->SetData  = Ip4Config2SetGateway;
   1920   DataItem->Status   = EFI_NOT_FOUND;
   1921 
   1922   DataItem           = &Instance->DataItem[Ip4Config2DataTypeDnsServer];
   1923   DataItem->SetData  = Ip4Config2SetDnsServer;
   1924   DataItem->Status   = EFI_NOT_FOUND;
   1925 
   1926   //
   1927   // Create the event used for DHCP.
   1928   //
   1929   Status = gBS->CreateEvent (
   1930                   EVT_NOTIFY_SIGNAL,
   1931                   TPL_CALLBACK,
   1932                   Ip4Config2OnDhcp4Event,
   1933                   Instance,
   1934                   &Instance->Dhcp4Event
   1935                   );
   1936   ASSERT_EFI_ERROR (Status);
   1937 
   1938   Instance->Configured  = TRUE;
   1939 
   1940   //
   1941   // Try to read the config data from NV variable.
   1942   //
   1943   Status = Ip4Config2ReadConfigData (IpSb->MacString, Instance);
   1944   if (Status == EFI_NOT_FOUND) {
   1945     Status = Ip4Config2WriteConfigData (IpSb->MacString, Instance);
   1946   }
   1947 
   1948   if (EFI_ERROR (Status)) {
   1949     return Status;
   1950   }
   1951 
   1952   //
   1953   // Try to set the configured parameter.
   1954   //
   1955   for (Index = Ip4Config2DataTypePolicy; Index < Ip4Config2DataTypeMaximum; Index++) {
   1956     DataItem = &IpSb->Ip4Config2Instance.DataItem[Index];
   1957     if (DataItem->Data.Ptr != NULL) {
   1958       DataItem->SetData (
   1959                   &IpSb->Ip4Config2Instance,
   1960                   DataItem->DataSize,
   1961                   DataItem->Data.Ptr
   1962                   );
   1963     }
   1964   }
   1965 
   1966   Instance->Ip4Config2.SetData              = EfiIp4Config2SetData;
   1967   Instance->Ip4Config2.GetData              = EfiIp4Config2GetData;
   1968   Instance->Ip4Config2.RegisterDataNotify   = EfiIp4Config2RegisterDataNotify;
   1969   Instance->Ip4Config2.UnregisterDataNotify = EfiIp4Config2UnregisterDataNotify;
   1970 
   1971   //
   1972   // Publish the IP4 configuration form
   1973   //
   1974   return Ip4Config2FormInit (Instance);
   1975 }
   1976 
   1977 
   1978 /**
   1979   Release an IP4_CONFIG2_INSTANCE.
   1980 
   1981   @param[in, out] Instance    The buffer of IP4_CONFIG2_INSTANCE to be freed.
   1982 
   1983 **/
   1984 VOID
   1985 Ip4Config2CleanInstance (
   1986   IN OUT IP4_CONFIG2_INSTANCE  *Instance
   1987   )
   1988 {
   1989   UINTN                 Index;
   1990   IP4_CONFIG2_DATA_ITEM *DataItem;
   1991 
   1992   if (Instance->DeclineAddress != NULL) {
   1993     FreePool (Instance->DeclineAddress);
   1994   }
   1995 
   1996   if (!Instance->Configured) {
   1997     return ;
   1998   }
   1999 
   2000   if (Instance->Dhcp4Handle != NULL) {
   2001 
   2002     Ip4Config2DestroyDhcp4 (Instance);
   2003   }
   2004 
   2005   //
   2006   // Close the event.
   2007   //
   2008   if (Instance->Dhcp4Event != NULL) {
   2009     gBS->CloseEvent (Instance->Dhcp4Event);
   2010   }
   2011 
   2012   for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {
   2013 
   2014     DataItem = &Instance->DataItem[Index];
   2015 
   2016     if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {
   2017       if (DataItem->Data.Ptr != NULL) {
   2018         FreePool (DataItem->Data.Ptr);
   2019       }
   2020       DataItem->Data.Ptr = NULL;
   2021       DataItem->DataSize = 0;
   2022     }
   2023 
   2024     NetMapClean (&Instance->DataItem[Index].EventMap);
   2025   }
   2026 
   2027   Ip4Config2FormUnload (Instance);
   2028 
   2029   RemoveEntryList (&Instance->Link);
   2030 }
   2031 
   2032