+/** @file\r
+ The implementation of EFI IPv4 Configuration II Protocol.\r
+\r
+ Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "Ip4Impl.h"\r
+\r
+LIST_ENTRY mIp4Config2InstanceList = {&mIp4Config2InstanceList, &mIp4Config2InstanceList};\r
+\r
+/**\r
+ The event process routine when the DHCPv4 service binding protocol is installed\r
+ in the system.\r
+\r
+ @param[in] Event Not used.\r
+ @param[in] Context Pointer to the IP4 config2 instance data.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4Config2OnDhcp4SbInstalled (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ );\r
+\r
+/**\r
+ Destroy the Dhcp4 child in IP4_CONFIG2_INSTANCE and release the resources.\r
+\r
+ @param[in, out] Instance The buffer of IP4 config2 instance to be freed.\r
+\r
+ @retval EFI_SUCCESS The child was successfully destroyed.\r
+ @retval Others Failed to destroy the child.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2DestroyDhcp4 (\r
+ IN OUT IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ EFI_STATUS Status;\r
+ EFI_DHCP4_PROTOCOL *Dhcp4;\r
+\r
+ Dhcp4 = Instance->Dhcp4;\r
+ ASSERT (Dhcp4 != NULL);\r
+\r
+ Dhcp4->Stop (Dhcp4);\r
+ Dhcp4->Configure (Dhcp4, NULL);\r
+ Instance->Dhcp4 = NULL;\r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+\r
+ //\r
+ // Close DHCPv4 protocol and destroy the child.\r
+ //\r
+ Status = gBS->CloseProtocol (\r
+ Instance->Dhcp4Handle,\r
+ &gEfiDhcp4ProtocolGuid,\r
+ IpSb->Image,\r
+ IpSb->Controller\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = NetLibDestroyServiceChild (\r
+ IpSb->Controller,\r
+ IpSb->Image,\r
+ &gEfiDhcp4ServiceBindingProtocolGuid,\r
+ Instance->Dhcp4Handle\r
+ );\r
+\r
+ Instance->Dhcp4Handle = NULL;\r
+\r
+ return Status; \r
+}\r
+\r
+/**\r
+ Start the DHCP configuration for this IP service instance.\r
+ It will locates the EFI_IP4_CONFIG2_PROTOCOL, then start the\r
+ DHCP configuration.\r
+\r
+ @param[in] Instance The IP4 config2 instance to configure.\r
+\r
+ @retval EFI_SUCCESS The auto configuration is successfull started.\r
+ @retval Others Failed to start auto configuration.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4StartAutoConfig (\r
+ IN IP4_CONFIG2_INSTANCE *Instance\r
+ );\r
+\r
+/**\r
+ Update the current policy to NewPolicy. During the transition\r
+ period, the default router list\r
+ and address list in all interfaces will be released.\r
+\r
+ @param[in] IpSb The IP4 service binding instance.\r
+ @param[in] NewPolicy The new policy to be updated to.\r
+\r
+**/\r
+VOID\r
+Ip4Config2OnPolicyChanged (\r
+ IN IP4_SERVICE *IpSb,\r
+ IN EFI_IP4_CONFIG2_POLICY NewPolicy\r
+ )\r
+{\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_ROUTE_TABLE *RouteTable;\r
+\r
+ //\r
+ // Currently there are only two policies: static and dhcp. Regardless of\r
+ // what transition is going on, i.e., static -> dhcp and dhcp ->\r
+ // static, we have to free default router table and all addresses.\r
+ //\r
+\r
+ if (IpSb->DefaultInterface != NULL) {\r
+ if (IpSb->DefaultRouteTable != NULL) {\r
+ Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
+ IpSb->DefaultRouteTable = NULL; \r
+ }\r
+\r
+ Ip4CancelReceive (IpSb->DefaultInterface);\r
+\r
+ Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
+ IpSb->DefaultInterface = NULL;\r
+ }\r
+\r
+ Ip4CleanAssembleTable (&IpSb->Assemble);\r
+\r
+ //\r
+ // Create new default interface and route table.\r
+ // \r
+ IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
+ if (IpIf == NULL) {\r
+ return ;\r
+ }\r
+\r
+ RouteTable = Ip4CreateRouteTable ();\r
+ if (RouteTable == NULL) {\r
+ Ip4FreeInterface (IpIf, NULL);\r
+ return ;\r
+ }\r
+ \r
+ IpSb->DefaultInterface = IpIf;\r
+ InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
+ IpSb->DefaultRouteTable = RouteTable;\r
+ Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
+\r
+ if (IpSb->State == IP4_SERVICE_CONFIGED) {\r
+ IpSb->State = IP4_SERVICE_UNSTARTED;\r
+ }\r
+\r
+ //\r
+ // Start the dhcp configuration.\r
+ //\r
+ if (NewPolicy == Ip4Config2PolicyDhcp) {\r
+ Ip4StartAutoConfig (&IpSb->Ip4Config2Instance);\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Signal the registered event. It is the callback routine for NetMapIterate.\r
+\r
+ @param[in] Map Points to the list of registered event.\r
+ @param[in] Item The registered event.\r
+ @param[in] Arg Not used.\r
+\r
+ @retval EFI_SUCCESS The event was signaled successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Ip4Config2SignalEvent (\r
+ IN NET_MAP *Map,\r
+ IN NET_MAP_ITEM *Item,\r
+ IN VOID *Arg\r
+ )\r
+{\r
+ gBS->SignalEvent ((EFI_EVENT) Item->Key);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Read the configuration data from variable storage according to the VarName and\r
+ gEfiIp4Config2ProtocolGuid. It checks the integrity of variable data. If the\r
+ data is corrupted, it clears the variable data to ZERO. Othewise, it outputs the\r
+ configuration data to IP4_CONFIG2_INSTANCE.\r
+\r
+ @param[in] VarName The pointer to the variable name\r
+ @param[in, out] Instance The pointer to the IP4 config2 instance data.\r
+\r
+ @retval EFI_NOT_FOUND The variable can not be found or already corrupted.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
+ @retval EFI_SUCCESS The configuration data was retrieved successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2ReadConfigData (\r
+ IN CHAR16 *VarName,\r
+ IN OUT IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN VarSize;\r
+ IP4_CONFIG2_VARIABLE *Variable;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+ UINTN Index;\r
+ IP4_CONFIG2_DATA_RECORD DataRecord;\r
+ CHAR8 *Data;\r
+\r
+ //\r
+ // Try to read the configuration variable.\r
+ //\r
+ VarSize = 0;\r
+ Status = gRT->GetVariable (\r
+ VarName,\r
+ &gEfiIp4Config2ProtocolGuid,\r
+ NULL,\r
+ &VarSize,\r
+ NULL\r
+ );\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ //\r
+ // Allocate buffer and read the config variable.\r
+ //\r
+ Variable = AllocatePool (VarSize);\r
+ if (Variable == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Status = gRT->GetVariable (\r
+ VarName,\r
+ &gEfiIp4Config2ProtocolGuid,\r
+ NULL,\r
+ &VarSize,\r
+ Variable\r
+ );\r
+ if (EFI_ERROR (Status) || (UINT16) (~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize)) != 0) {\r
+ //\r
+ // GetVariable still error or the variable is corrupted.\r
+ // Fall back to the default value.\r
+ //\r
+ FreePool (Variable);\r
+\r
+ //\r
+ // Remove the problematic variable and return EFI_NOT_FOUND, a new\r
+ // variable will be set again.\r
+ //\r
+ gRT->SetVariable (\r
+ VarName,\r
+ &gEfiIp4Config2ProtocolGuid,\r
+ IP4_CONFIG2_VARIABLE_ATTRIBUTE,\r
+ 0,\r
+ NULL\r
+ );\r
+\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ \r
+ for (Index = 0; Index < Variable->DataRecordCount; Index++) {\r
+\r
+ CopyMem (&DataRecord, &Variable->DataRecord[Index], sizeof (DataRecord));\r
+\r
+ DataItem = &Instance->DataItem[DataRecord.DataType];\r
+ if (DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED) &&\r
+ (DataItem->DataSize != DataRecord.DataSize)\r
+ ) {\r
+ //\r
+ // Perhaps a corrupted data record...\r
+ //\r
+ continue;\r
+ }\r
+\r
+ if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {\r
+ //\r
+ // This data item has variable length data.\r
+ //\r
+ DataItem->Data.Ptr = AllocatePool (DataRecord.DataSize);\r
+ if (DataItem->Data.Ptr == NULL) {\r
+ //\r
+ // no memory resource\r
+ //\r
+ continue;\r
+ }\r
+ }\r
+\r
+ Data = (CHAR8 *) Variable + DataRecord.Offset;\r
+ CopyMem (DataItem->Data.Ptr, Data, DataRecord.DataSize);\r
+\r
+ DataItem->DataSize = DataRecord.DataSize;\r
+ DataItem->Status = EFI_SUCCESS;\r
+ }\r
+\r
+ FreePool (Variable);\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Write the configuration data from IP4_CONFIG2_INSTANCE to variable storage.\r
+\r
+ @param[in] VarName The pointer to the variable name.\r
+ @param[in] Instance The pointer to the IP4 config2 instance data.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
+ @retval EFI_SUCCESS The configuration data is written successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2WriteConfigData (\r
+ IN CHAR16 *VarName,\r
+ IN IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ UINTN Index;\r
+ UINTN VarSize;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+ IP4_CONFIG2_VARIABLE *Variable;\r
+ IP4_CONFIG2_DATA_RECORD *DataRecord;\r
+ CHAR8 *Heap;\r
+ EFI_STATUS Status;\r
+\r
+ VarSize = sizeof (IP4_CONFIG2_VARIABLE) - sizeof (IP4_CONFIG2_DATA_RECORD);\r
+\r
+ for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {\r
+\r
+ DataItem = &Instance->DataItem[Index];\r
+ if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {\r
+\r
+ VarSize += sizeof (IP4_CONFIG2_DATA_RECORD) + DataItem->DataSize;\r
+ }\r
+ }\r
+\r
+ Variable = AllocatePool (VarSize);\r
+ if (Variable == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Heap = (CHAR8 *) Variable + VarSize;\r
+ Variable->DataRecordCount = 0;\r
+\r
+ for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {\r
+\r
+ DataItem = &Instance->DataItem[Index];\r
+ if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_VOLATILE) && !EFI_ERROR (DataItem->Status)) {\r
+\r
+ Heap -= DataItem->DataSize;\r
+ CopyMem (Heap, DataItem->Data.Ptr, DataItem->DataSize);\r
+\r
+ DataRecord = &Variable->DataRecord[Variable->DataRecordCount];\r
+ DataRecord->DataType = (EFI_IP4_CONFIG2_DATA_TYPE) Index;\r
+ DataRecord->DataSize = (UINT32) DataItem->DataSize;\r
+ DataRecord->Offset = (UINT16) (Heap - (CHAR8 *) Variable);\r
+\r
+ Variable->DataRecordCount++;\r
+ }\r
+ }\r
+\r
+ Variable->Checksum = 0;\r
+ Variable->Checksum = (UINT16) ~NetblockChecksum ((UINT8 *) Variable, (UINT32) VarSize);\r
+\r
+ Status = gRT->SetVariable (\r
+ VarName,\r
+ &gEfiIp4Config2ProtocolGuid,\r
+ IP4_CONFIG2_VARIABLE_ATTRIBUTE,\r
+ VarSize,\r
+ Variable\r
+ );\r
+\r
+ FreePool (Variable);\r
+\r
+ return Status;\r
+}\r
+\r
+\r
+/**\r
+ Build a EFI_IP4_ROUTE_TABLE to be returned to the caller of GetModeData. \r
+ The EFI_IP4_ROUTE_TABLE is clumsy to use in the internal operation of the \r
+ IP4 driver.\r
+\r
+ @param[in] IpSb The IP4 service binding instance.\r
+ @param[out] Table The built IP4 route table.\r
+\r
+ @retval EFI_SUCCESS The route table is successfully build\r
+ @retval EFI_NOT_FOUND Failed to allocate the memory for the rotue table.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2BuildDefaultRouteTable (\r
+ IN IP4_SERVICE *IpSb,\r
+ OUT EFI_IP4_ROUTE_TABLE *Table\r
+ )\r
+{\r
+ LIST_ENTRY *Entry; \r
+ IP4_ROUTE_ENTRY *RtEntry;\r
+ UINT32 Count;\r
+ INT32 Index;\r
+\r
+ if (IpSb->DefaultRouteTable == NULL) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Count = IpSb->DefaultRouteTable->TotalNum;\r
+\r
+ if (Count == 0) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // Copy the route entry to EFI route table. Keep the order of\r
+ // route entry copied from most specific to default route. That\r
+ // is, interlevel the route entry from the instance's route area\r
+ // and those from the default route table's route area.\r
+ //\r
+ Count = 0;\r
+\r
+ for (Index = IP4_MASK_NUM - 1; Index >= 0; Index--) {\r
+\r
+ NET_LIST_FOR_EACH (Entry, &(IpSb->DefaultRouteTable->RouteArea[Index])) {\r
+ RtEntry = NET_LIST_USER_STRUCT (Entry, IP4_ROUTE_ENTRY, Link);\r
+\r
+ EFI_IP4 (Table[Count].SubnetAddress) = HTONL (RtEntry->Dest & RtEntry->Netmask);\r
+ EFI_IP4 (Table[Count].SubnetMask) = HTONL (RtEntry->Netmask);\r
+ EFI_IP4 (Table[Count].GatewayAddress) = HTONL (RtEntry->NextHop);\r
+\r
+ Count++;\r
+ }\r
+\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The event process routine when the DHCPv4 service binding protocol is installed\r
+ in the system.\r
+\r
+ @param[in] Event Not used.\r
+ @param[in] Context The pointer to the IP4 config2 instance data.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4Config2OnDhcp4SbInstalled (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_CONFIG2_INSTANCE *Instance;\r
+\r
+ Instance = (IP4_CONFIG2_INSTANCE *) Context;\r
+\r
+ if ((Instance->Dhcp4Handle != NULL) || (Instance->Policy != Ip4Config2PolicyDhcp)) {\r
+ //\r
+ // The DHCP4 child is already created or the policy is no longer DHCP.\r
+ //\r
+ return ;\r
+ }\r
+\r
+ Ip4StartAutoConfig (Instance);\r
+}\r
+\r
+/**\r
+ Set the station address and subnetmask for the default interface.\r
+\r
+ @param[in] Instance The pointer to the IP4 config2 instance data.\r
+ @param[in] StationAddress Ip address to be set.\r
+ @param[in] SubnetMask Subnet to be set.\r
+\r
+ @retval EFI_SUCCESS Set default address successful. \r
+ @retval Others Some errors occur in setting. \r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetDefaultAddr (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN IP4_ADDR StationAddress,\r
+ IN IP4_ADDR SubnetMask\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IP4_SERVICE *IpSb;\r
+ IP4_INTERFACE *IpIf;\r
+ IP4_PROTOCOL *Ip4Instance;\r
+ EFI_ARP_PROTOCOL *Arp;\r
+ LIST_ENTRY *Entry;\r
+ IP4_ADDR Subnet;\r
+ IP4_ROUTE_TABLE *RouteTable;\r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+ IpIf = IpSb->DefaultInterface;\r
+ ASSERT (IpIf != NULL);\r
+\r
+ if ((IpIf->Ip == StationAddress) && (IpIf->SubnetMask == SubnetMask)) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // The default address is changed, free the previous interface first.\r
+ //\r
+ if (IpSb->DefaultRouteTable != NULL) {\r
+ Ip4FreeRouteTable (IpSb->DefaultRouteTable);\r
+ IpSb->DefaultRouteTable = NULL; \r
+ }\r
+\r
+ Ip4CancelReceive (IpSb->DefaultInterface);\r
+ Ip4FreeInterface (IpSb->DefaultInterface, NULL);\r
+ IpSb->DefaultInterface = NULL;\r
+ //\r
+ // Create new default interface and route table.\r
+ // \r
+ IpIf = Ip4CreateInterface (IpSb->Mnp, IpSb->Controller, IpSb->Image);\r
+ if (IpIf == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ RouteTable = Ip4CreateRouteTable ();\r
+ if (RouteTable == NULL) {\r
+ Ip4FreeInterface (IpIf, NULL);\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ \r
+ IpSb->DefaultInterface = IpIf;\r
+ InsertHeadList (&IpSb->Interfaces, &IpIf->Link);\r
+ IpSb->DefaultRouteTable = RouteTable;\r
+ Ip4ReceiveFrame (IpIf, NULL, Ip4AccpetFrame, IpSb);\r
+\r
+ if (IpSb->State == IP4_SERVICE_CONFIGED) {\r
+ IpSb->State = IP4_SERVICE_UNSTARTED;\r
+ }\r
+\r
+ Status = Ip4SetAddress (IpIf, StationAddress, SubnetMask);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (IpIf->Arp != NULL) {\r
+ // \r
+ // A non-NULL IpIf->Arp here means a new ARP child is created when setting default address, \r
+ // but some IP children may have referenced the default interface before it is configured,\r
+ // these IP instances also consume this ARP protocol so they need to open it BY_CHILD_CONTROLLER.\r
+ //\r
+ Arp = NULL;\r
+ NET_LIST_FOR_EACH (Entry, &IpIf->IpInstances) {\r
+ Ip4Instance = NET_LIST_USER_STRUCT_S (Entry, IP4_PROTOCOL, AddrLink, IP4_PROTOCOL_SIGNATURE);\r
+ Status = gBS->OpenProtocol (\r
+ IpIf->ArpHandle,\r
+ &gEfiArpProtocolGuid,\r
+ (VOID **) &Arp,\r
+ gIp4DriverBinding.DriverBindingHandle,\r
+ Ip4Instance->Handle,\r
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ }\r
+ }\r
+\r
+ Ip4AddRoute (\r
+ IpSb->DefaultRouteTable,\r
+ StationAddress,\r
+ SubnetMask,\r
+ IP4_ALLZERO_ADDRESS\r
+ );\r
+\r
+ //\r
+ // Add a route for the connected network.\r
+ //\r
+ Subnet = StationAddress & SubnetMask;\r
+\r
+ Ip4AddRoute (\r
+ IpSb->DefaultRouteTable,\r
+ Subnet,\r
+ SubnetMask,\r
+ IP4_ALLZERO_ADDRESS\r
+ );\r
+\r
+ IpSb->State = IP4_SERVICE_CONFIGED;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Set the station address, subnetmask and gateway address for the default interface.\r
+\r
+ @param[in] Instance The pointer to the IP4 config2 instance data. \r
+ @param[in] StationAddress Ip address to be set.\r
+ @param[in] SubnetMask Subnet to be set.\r
+ @param[in] GatewayAddress Gateway to be set.\r
+\r
+ @retval EFI_SUCCESS Set default If successful. \r
+ @retval Others Errors occur as indicated. \r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetDefaultIf (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN IP4_ADDR StationAddress,\r
+ IN IP4_ADDR SubnetMask,\r
+ IN IP4_ADDR GatewayAddress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ IP4_SERVICE *IpSb;\r
+\r
+ Status = Ip4Config2SetDefaultAddr (Instance, StationAddress, SubnetMask);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Create a route if there is a default router.\r
+ //\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+ if (GatewayAddress != IP4_ALLZERO_ADDRESS) {\r
+ Ip4AddRoute (\r
+ IpSb->DefaultRouteTable,\r
+ IP4_ALLZERO_ADDRESS,\r
+ IP4_ALLZERO_ADDRESS,\r
+ GatewayAddress\r
+ ); \r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+ Release all the DHCP related resources.\r
+\r
+ @param Instance The IP4 config2 instance.\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+Ip4Config2CleanDhcp4 (\r
+ IN IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+\r
+ if (Instance->Dhcp4 != NULL) {\r
+ Instance->Dhcp4->Stop (Instance->Dhcp4);\r
+\r
+ gBS->CloseProtocol (\r
+ Instance->Dhcp4Handle,\r
+ &gEfiDhcp4ProtocolGuid,\r
+ IpSb->Image,\r
+ IpSb->Controller\r
+ );\r
+\r
+ Instance->Dhcp4 = NULL;\r
+ }\r
+\r
+ if (Instance->Dhcp4Handle != NULL) {\r
+ NetLibDestroyServiceChild (\r
+ IpSb->Controller,\r
+ IpSb->Image,\r
+ &gEfiDhcp4ServiceBindingProtocolGuid,\r
+ Instance->Dhcp4Handle\r
+ );\r
+\r
+ Instance->Dhcp4Handle = NULL;\r
+ }\r
+\r
+ if (Instance->Dhcp4Event != NULL) {\r
+ gBS->CloseEvent (Instance->Dhcp4Event);\r
+ Instance->Dhcp4Event = NULL;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Callback function when DHCP process finished. It will save the\r
+ retrieved IP configure parameter from DHCP to the NVRam.\r
+\r
+ @param Event The callback event\r
+ @param Context Opaque context to the callback\r
+\r
+ @return None\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4Config2OnDhcp4Complete (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ IP4_CONFIG2_INSTANCE *Instance;\r
+ EFI_DHCP4_MODE_DATA Dhcp4Mode;\r
+ EFI_STATUS Status;\r
+ IP4_ADDR StationAddress;\r
+ IP4_ADDR SubnetMask;\r
+ IP4_ADDR GatewayAddress;\r
+\r
+ Instance = (IP4_CONFIG2_INSTANCE *) Context;\r
+ ASSERT (Instance->Dhcp4 != NULL);\r
+\r
+ //\r
+ // Get the DHCP retrieved parameters\r
+ //\r
+ Status = Instance->Dhcp4->GetModeData (Instance->Dhcp4, &Dhcp4Mode);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+\r
+ if (Dhcp4Mode.State == Dhcp4Bound) {\r
+ StationAddress = EFI_NTOHL (Dhcp4Mode.ClientAddress);\r
+ SubnetMask = EFI_NTOHL (Dhcp4Mode.SubnetMask);\r
+ GatewayAddress = EFI_NTOHL (Dhcp4Mode.RouterAddress);\r
+\r
+ Status = Ip4Config2SetDefaultIf (Instance, StationAddress, SubnetMask, GatewayAddress);\r
+ if (EFI_ERROR (Status)) {\r
+ goto Exit;\r
+ }\r
+ \r
+ Instance->DhcpSuccess = TRUE;\r
+ }\r
+\r
+Exit:\r
+ Ip4Config2CleanDhcp4 (Instance);\r
+ DispatchDpc ();\r
+}\r
+\r
+\r
+/**\r
+ Start the DHCP configuration for this IP service instance.\r
+ It will locates the EFI_IP4_CONFIG2_PROTOCOL, then start the\r
+ DHCP configuration.\r
+\r
+ @param[in] Instance The IP4 config2 instance to configure\r
+\r
+ @retval EFI_SUCCESS The auto configuration is successfull started\r
+ @retval Others Failed to start auto configuration.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4StartAutoConfig (\r
+ IN IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ EFI_DHCP4_PROTOCOL *Dhcp4;\r
+ EFI_DHCP4_MODE_DATA Dhcp4Mode;\r
+ EFI_DHCP4_PACKET_OPTION *OptionList[1];\r
+ IP4_CONFIG2_DHCP4_OPTION ParaList;\r
+ EFI_STATUS Status;\r
+ \r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+\r
+ if (IpSb->State > IP4_SERVICE_UNSTARTED) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ //\r
+ // A host must not invoke DHCP configuration if it is already\r
+ // participating in the DHCP configuraiton process.\r
+ //\r
+ if (Instance->Dhcp4Handle != NULL) {\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ Status = NetLibCreateServiceChild (\r
+ IpSb->Controller,\r
+ IpSb->Image,\r
+ &gEfiDhcp4ServiceBindingProtocolGuid,\r
+ &Instance->Dhcp4Handle\r
+ );\r
+\r
+ if (Status == EFI_UNSUPPORTED) {\r
+ //\r
+ // No DHCPv4 Service Binding protocol, register a notify.\r
+ //\r
+ if (Instance->Dhcp4SbNotifyEvent == NULL) {\r
+ Instance->Dhcp4SbNotifyEvent = EfiCreateProtocolNotifyEvent (\r
+ &gEfiDhcp4ServiceBindingProtocolGuid,\r
+ TPL_CALLBACK,\r
+ Ip4Config2OnDhcp4SbInstalled,\r
+ (VOID *) Instance,\r
+ &Instance->Registration\r
+ );\r
+ }\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ if (Instance->Dhcp4SbNotifyEvent != NULL) {\r
+ gBS->CloseEvent (Instance->Dhcp4SbNotifyEvent);\r
+ }\r
+\r
+ Status = gBS->OpenProtocol (\r
+ Instance->Dhcp4Handle,\r
+ &gEfiDhcp4ProtocolGuid,\r
+ (VOID **) &Instance->Dhcp4,\r
+ IpSb->Image,\r
+ IpSb->Controller,\r
+ EFI_OPEN_PROTOCOL_BY_DRIVER\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+\r
+ //\r
+ // Check the current DHCP status, if the DHCP process has\r
+ // already finished, return now.\r
+ //\r
+ Dhcp4 = Instance->Dhcp4;\r
+ Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4Mode);\r
+\r
+ if (Dhcp4Mode.State == Dhcp4Bound) {\r
+ Ip4Config2OnDhcp4Complete (NULL, Instance);\r
+ return EFI_SUCCESS;\r
+\r
+ }\r
+\r
+ //\r
+ // Try to start the DHCP process. Use most of the current\r
+ // DHCP configuration to avoid problems if some DHCP client\r
+ // yields the control of this DHCP service to us.\r
+ //\r
+ ParaList.Head.OpCode = DHCP_TAG_PARA_LIST;\r
+ ParaList.Head.Length = 2;\r
+ ParaList.Head.Data[0] = DHCP_TAG_NETMASK;\r
+ ParaList.Route = DHCP_TAG_ROUTER;\r
+ OptionList[0] = &ParaList.Head;\r
+ Dhcp4Mode.ConfigData.OptionCount = 1;\r
+ Dhcp4Mode.ConfigData.OptionList = OptionList;\r
+\r
+ Status = Dhcp4->Configure (Dhcp4, &Dhcp4Mode.ConfigData);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ //\r
+ // Start the DHCP process\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ip4Config2OnDhcp4Complete,\r
+ Instance,\r
+ &Instance->Dhcp4Event\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Status = Dhcp4->Start (Dhcp4, Instance->Dhcp4Event);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+ \r
+ IpSb->State = IP4_SERVICE_STARTED;\r
+ DispatchDpc ();\r
+ return EFI_SUCCESS;\r
+\r
+}\r
+\r
+\r
+\r
+/**\r
+ The work function is to get the interface information of the communication \r
+ device this IP4_CONFIG2_INSTANCE manages.\r
+\r
+ @param[in] Instance Pointer to the IP4 config2 instance data.\r
+ @param[in, out] DataSize On input, in bytes, the size of Data. On output, in\r
+ bytes, the size of buffer required to store the specified\r
+ configuration data.\r
+ @param[in] Data The data buffer in which the configuration data is returned.\r
+ Ignored if DataSize is ZERO.\r
+\r
+ @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified\r
+ configuration data, and the required size is\r
+ returned in DataSize.\r
+ @retval EFI_SUCCESS The specified configuration data was obtained.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2GetIfInfo (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN OUT UINTN *DataSize,\r
+ IN VOID *Data OPTIONAL\r
+ )\r
+{\r
+\r
+ IP4_SERVICE *IpSb;\r
+ UINTN Length;\r
+ IP4_CONFIG2_DATA_ITEM *Item;\r
+ EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo;\r
+ IP4_ADDR Address;\r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+ Length = sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO);\r
+\r
+ if (IpSb->DefaultRouteTable != NULL) {\r
+ Length += IpSb->DefaultRouteTable->TotalNum * sizeof (EFI_IP4_ROUTE_TABLE);\r
+ }\r
+ \r
+ if (*DataSize < Length) {\r
+ *DataSize = Length;\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+\r
+ //\r
+ // Copy the fixed size part of the interface info.\r
+ //\r
+ Item = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];\r
+ IfInfo = (EFI_IP4_CONFIG2_INTERFACE_INFO *) Data;\r
+ CopyMem (IfInfo, Item->Data.Ptr, sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));\r
+\r
+ //\r
+ // Update the address info.\r
+ //\r
+ if (IpSb->DefaultInterface != NULL) {\r
+ Address = HTONL (IpSb->DefaultInterface->Ip);\r
+ CopyMem (&IfInfo->StationAddress, &Address, sizeof (EFI_IPv4_ADDRESS));\r
+ Address = HTONL (IpSb->DefaultInterface->SubnetMask);\r
+ CopyMem (&IfInfo->SubnetMask, &Address, sizeof (EFI_IPv4_ADDRESS));\r
+ }\r
+\r
+ if (IpSb->DefaultRouteTable != NULL) {\r
+ IfInfo->RouteTableSize = IpSb->DefaultRouteTable->TotalNum;\r
+ IfInfo->RouteTable = (EFI_IP4_ROUTE_TABLE *) ((UINT8 *) Data + sizeof (EFI_IP4_CONFIG2_INTERFACE_INFO));\r
+\r
+ Ip4Config2BuildDefaultRouteTable (IpSb, IfInfo->RouteTable); \r
+ }\r
+ \r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The work function is to set the general configuration policy for the EFI IPv4 network \r
+ stack that is running on the communication device managed by this IP4_CONFIG2_INSTANCE.\r
+ The policy will affect other configuration settings.\r
+\r
+ @param[in] Instance Pointer to the IP4 config2 instance data.\r
+ @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
+ @param[in] Data The data buffer to set.\r
+\r
+ @retval EFI_INVALID_PARAMETER The to be set policy is invalid.\r
+ @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
+ @retval EFI_ABORTED The new policy equals the current policy.\r
+ @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
+ network stack was set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetPolicy (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ EFI_IP4_CONFIG2_POLICY NewPolicy;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+ IP4_SERVICE *IpSb;\r
+\r
+ if (DataSize != sizeof (EFI_IP4_CONFIG2_POLICY)) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ NewPolicy = *((EFI_IP4_CONFIG2_POLICY *) Data);\r
+\r
+ if (NewPolicy >= Ip4Config2PolicyMax) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (NewPolicy == Instance->Policy) {\r
+ if (NewPolicy != Ip4Config2PolicyDhcp || Instance->DhcpSuccess) {\r
+ return EFI_ABORTED;\r
+ }\r
+ \r
+ } else {\r
+ if (NewPolicy == Ip4Config2PolicyDhcp) {\r
+ //\r
+ // The policy is changed from static to dhcp:\r
+ // Clean the ManualAddress, Gateway and DnsServers, shrink the variable\r
+ // data size, and fire up all the related events.\r
+ //\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ FreePool (DataItem->Data.Ptr);\r
+ }\r
+ DataItem->Data.Ptr = NULL;\r
+ DataItem->DataSize = 0;\r
+ DataItem->Status = EFI_NOT_FOUND;\r
+ NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ FreePool (DataItem->Data.Ptr);\r
+ }\r
+ DataItem->Data.Ptr = NULL;\r
+ DataItem->DataSize = 0;\r
+ DataItem->Status = EFI_NOT_FOUND;\r
+ NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ FreePool (DataItem->Data.Ptr);\r
+ }\r
+ DataItem->Data.Ptr = NULL;\r
+ DataItem->DataSize = 0;\r
+ DataItem->Status = EFI_NOT_FOUND;\r
+ NetMapIterate (&DataItem->EventMap, Ip4Config2SignalEvent, NULL);\r
+ } else {\r
+ //\r
+ // The policy is changed from dhcp to static. Stop the DHCPv4 process\r
+ // and destroy the DHCPv4 child.\r
+ //\r
+ if (Instance->Dhcp4Handle != NULL) {\r
+ Ip4Config2DestroyDhcp4 (Instance);\r
+ }\r
+ \r
+ //\r
+ // Close the event.\r
+ //\r
+ if (Instance->Dhcp4Event != NULL) {\r
+ gBS->CloseEvent (Instance->Dhcp4Event);\r
+ }\r
+ }\r
+ }\r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+ Ip4Config2OnPolicyChanged (IpSb, NewPolicy);\r
+\r
+ Instance->Policy = NewPolicy;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The work function is to set the station addresses manually for the EFI IPv4 \r
+ network stack. It is only configurable when the policy is Ip4Config2PolicyStatic.\r
+\r
+ @param[in] Instance Pointer to the IP4 config2 instance data.\r
+ @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
+ @param[in] Data The data buffer to set.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
+ @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
+ under the current policy.\r
+ @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete the operation.\r
+ @retval EFI_NOT_READY An asynchrous process is invoked to set the specified\r
+ configuration data, and the process is not finished.\r
+ @retval EFI_ABORTED The manual addresses to be set equal current\r
+ configuration.\r
+ @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
+ network stack was set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetMaunualAddress (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ EFI_IP4_CONFIG2_MANUAL_ADDRESS NewAddress;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+ EFI_STATUS Status;\r
+ IP4_ADDR StationAddress;\r
+ IP4_ADDR SubnetMask;\r
+ VOID *Ptr;\r
+\r
+ ASSERT (Instance->DataItem[Ip4Config2DataTypeManualAddress].Status != EFI_NOT_READY);\r
+\r
+ if (((DataSize % sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS)) != 0) || (DataSize == 0)) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (Instance->Policy != Ip4Config2PolicyStatic) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ NewAddress = *((EFI_IP4_CONFIG2_MANUAL_ADDRESS *) Data);\r
+\r
+ //\r
+ // Store the new data, and init the DataItem status to EFI_NOT_READY because\r
+ // we may have an asynchronous configuration process.\r
+ //\r
+ Ptr = AllocateCopyPool (DataSize, Data);\r
+ if (Ptr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ FreePool (DataItem->Data.Ptr);\r
+ }\r
+ \r
+ DataItem->Data.Ptr = Ptr;\r
+ DataItem->DataSize = DataSize;\r
+ DataItem->Status = EFI_NOT_READY;\r
+\r
+ StationAddress = EFI_NTOHL (NewAddress.Address);\r
+ SubnetMask = EFI_NTOHL (NewAddress.SubnetMask);\r
+\r
+ Status = Ip4Config2SetDefaultAddr (Instance, StationAddress, SubnetMask);\r
+ if (EFI_ERROR (Status)) {\r
+ goto ON_EXIT;\r
+ } \r
+\r
+ DataItem->Status = EFI_SUCCESS; \r
+\r
+ON_EXIT:\r
+ if (EFI_ERROR (DataItem->Status)) {\r
+ if (Ptr != NULL) {\r
+ FreePool (Ptr);\r
+ }\r
+ DataItem->Data.Ptr = NULL; \r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ The work function is to set the gateway addresses manually for the EFI IPv4 \r
+ network stack that is running on the communication device that this EFI IPv4 \r
+ Configuration Protocol manages. It is not configurable when the policy is\r
+ Ip4Config2PolicyDhcp. The gateway addresses must be unicast IPv4 addresses.\r
+\r
+ @param[in] Instance The pointer to the IP4 config2 instance data.\r
+ @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
+ @param[in] Data The data buffer to set. This points to an array of\r
+ EFI_IPv6_ADDRESS instances.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
+ @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
+ under the current policy.\r
+ @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resource to complete the operation.\r
+ @retval EFI_ABORTED The manual gateway addresses to be set equal the\r
+ current configuration.\r
+ @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
+ network stack was set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetGateway (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+ IP4_ADDR Gateway;\r
+\r
+ UINTN Index1;\r
+ UINTN Index2;\r
+ EFI_IPv4_ADDRESS *OldGateway;\r
+ EFI_IPv4_ADDRESS *NewGateway;\r
+ UINTN OldGatewayCount;\r
+ UINTN NewGatewayCount;\r
+ BOOLEAN OneRemoved;\r
+ BOOLEAN OneAdded;\r
+ VOID *Tmp;\r
+\r
+ if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (Instance->Policy != Ip4Config2PolicyStatic) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+\r
+ NewGateway = (EFI_IPv4_ADDRESS *) Data;\r
+ NewGatewayCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+ for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+ CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));\r
+ \r
+ if (!NetIp4IsUnicast (NTOHL (Gateway), 0)) {\r
+\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (Index2 = Index1 + 1; Index2 < NewGatewayCount; Index2++) {\r
+ if (EFI_IP4_EQUAL (NewGateway + Index1, NewGateway + Index2)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+ }\r
+ \r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];\r
+ OldGateway = DataItem->Data.Gateway;\r
+ OldGatewayCount = DataItem->DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+ OneRemoved = FALSE;\r
+ OneAdded = FALSE;\r
+\r
+ if (NewGatewayCount != OldGatewayCount) {\r
+ Tmp = AllocatePool (DataSize);\r
+ if (Tmp == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ Tmp = NULL;\r
+ }\r
+\r
+ for (Index1 = 0; Index1 < OldGatewayCount; Index1++) {\r
+ //\r
+ // Remove this route entry.\r
+ //\r
+ CopyMem (&Gateway, OldGateway + Index1, sizeof (IP4_ADDR));\r
+ Ip4DelRoute (\r
+ IpSb->DefaultRouteTable,\r
+ IP4_ALLZERO_ADDRESS,\r
+ IP4_ALLZERO_ADDRESS,\r
+ NTOHL (Gateway)\r
+ );\r
+ OneRemoved = TRUE;\r
+\r
+ }\r
+\r
+ for (Index1 = 0; Index1 < NewGatewayCount; Index1++) {\r
+ CopyMem (&Gateway, NewGateway + Index1, sizeof (IP4_ADDR));\r
+ Ip4AddRoute (\r
+ IpSb->DefaultRouteTable,\r
+ IP4_ALLZERO_ADDRESS,\r
+ IP4_ALLZERO_ADDRESS,\r
+ NTOHL (Gateway)\r
+ ); \r
+\r
+ OneAdded = TRUE;\r
+ }\r
+\r
+\r
+ if (!OneRemoved && !OneAdded) {\r
+ DataItem->Status = EFI_SUCCESS;\r
+ return EFI_ABORTED;\r
+ } else {\r
+\r
+ if (Tmp != NULL) {\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ FreePool (DataItem->Data.Ptr);\r
+ }\r
+ DataItem->Data.Ptr = Tmp;\r
+ }\r
+\r
+ CopyMem (DataItem->Data.Ptr, Data, DataSize);\r
+ DataItem->DataSize = DataSize;\r
+ DataItem->Status = EFI_SUCCESS;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ The work function is to set the DNS server list for the EFI IPv4 network \r
+ stack running on the communication device that this EFI_IP4_CONFIG2_PROTOCOL \r
+ manages. It is not configurable when the policy is Ip4Config2PolicyDhcp. \r
+ The DNS server addresses must be unicast IPv4 addresses.\r
+\r
+ @param[in] Instance The pointer to the IP4 config2 instance data.\r
+ @param[in] DataSize The size of the buffer pointed to by Data in bytes.\r
+ @param[in] Data The data buffer to set, points to an array of\r
+ EFI_IPv4_ADDRESS instances.\r
+\r
+ @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type.\r
+ @retval EFI_WRITE_PROTECTED The specified configuration data cannot be set\r
+ under the current policy.\r
+ @retval EFI_INVALID_PARAMETER One or more fields in Data is invalid.\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
+ @retval EFI_ABORTED The DNS server addresses to be set equal the current\r
+ configuration.\r
+ @retval EFI_SUCCESS The specified configuration data for the EFI IPv4\r
+ network stack was set.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2SetDnsServer (\r
+ IN IP4_CONFIG2_INSTANCE *Instance,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ UINTN OldIndex;\r
+ UINTN NewIndex;\r
+ UINTN Index1;\r
+ EFI_IPv4_ADDRESS *OldDns;\r
+ EFI_IPv4_ADDRESS *NewDns;\r
+ UINTN OldDnsCount;\r
+ UINTN NewDnsCount;\r
+ IP4_CONFIG2_DATA_ITEM *Item;\r
+ BOOLEAN OneAdded;\r
+ VOID *Tmp;\r
+ IP4_ADDR DnsAddress;\r
+\r
+ if ((DataSize % sizeof (EFI_IPv4_ADDRESS) != 0) || (DataSize == 0)) {\r
+ return EFI_BAD_BUFFER_SIZE;\r
+ }\r
+\r
+ if (Instance->Policy != Ip4Config2PolicyStatic) {\r
+ return EFI_WRITE_PROTECTED;\r
+ }\r
+\r
+ Item = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\r
+ NewDns = (EFI_IPv4_ADDRESS *) Data;\r
+ OldDns = Item->Data.DnsServers;\r
+ NewDnsCount = DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+ OldDnsCount = Item->DataSize / sizeof (EFI_IPv4_ADDRESS);\r
+ OneAdded = FALSE;\r
+\r
+ if (NewDnsCount != OldDnsCount) {\r
+ Tmp = AllocatePool (DataSize);\r
+ if (Tmp == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ } else {\r
+ Tmp = NULL;\r
+ }\r
+\r
+ for (NewIndex = 0; NewIndex < NewDnsCount; NewIndex++) {\r
+ CopyMem (&DnsAddress, NewDns + NewIndex, sizeof (IP4_ADDR));\r
+\r
+ if (!NetIp4IsUnicast (NTOHL (DnsAddress), 0)) {\r
+ //\r
+ // The dns server address must be unicast.\r
+ //\r
+ FreePool (Tmp);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ for (Index1 = NewIndex + 1; Index1 < NewDnsCount; Index1++) {\r
+ if (EFI_IP4_EQUAL (NewDns + NewIndex, NewDns + Index1)) {\r
+ FreePool (Tmp);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ }\r
+\r
+ if (OneAdded) {\r
+ //\r
+ // If any address in the new setting is not in the old settings, skip the\r
+ // comparision below.\r
+ //\r
+ continue;\r
+ }\r
+\r
+ for (OldIndex = 0; OldIndex < OldDnsCount; OldIndex++) {\r
+ if (EFI_IP4_EQUAL (NewDns + NewIndex, OldDns + OldIndex)) {\r
+ //\r
+ // If found break out.\r
+ //\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (OldIndex == OldDnsCount) {\r
+ OneAdded = TRUE;\r
+ }\r
+ }\r
+\r
+ if (!OneAdded && (DataSize == Item->DataSize)) {\r
+ //\r
+ // No new item is added and the size is the same.\r
+ //\r
+ Item->Status = EFI_SUCCESS;\r
+ return EFI_ABORTED;\r
+ } else {\r
+ if (Tmp != NULL) {\r
+ if (Item->Data.Ptr != NULL) {\r
+ FreePool (Item->Data.Ptr);\r
+ } \r
+ Item->Data.Ptr = Tmp;\r
+ }\r
+\r
+ CopyMem (Item->Data.Ptr, Data, DataSize);\r
+ Item->DataSize = DataSize;\r
+ Item->Status = EFI_SUCCESS;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+}\r
+\r
+/**\r
+ Generate the operational state of the interface this IP4 config2 instance manages\r
+ and output in EFI_IP4_CONFIG2_INTERFACE_INFO.\r
+\r
+ @param[in] IpSb The pointer to the IP4 service binding instance.\r
+ @param[out] IfInfo The pointer to the IP4 config2 interface information structure.\r
+\r
+**/\r
+VOID\r
+Ip4Config2InitIfInfo (\r
+ IN IP4_SERVICE *IpSb,\r
+ OUT EFI_IP4_CONFIG2_INTERFACE_INFO *IfInfo\r
+ )\r
+{\r
+ IfInfo->Name[0] = L'e';\r
+ IfInfo->Name[1] = L't';\r
+ IfInfo->Name[2] = L'h';\r
+ IfInfo->Name[3] = (CHAR16) (L'0' + IpSb->Ip4Config2Instance.IfIndex);\r
+ IfInfo->Name[4] = 0;\r
+\r
+ IfInfo->IfType = IpSb->SnpMode.IfType;\r
+ IfInfo->HwAddressSize = IpSb->SnpMode.HwAddressSize;\r
+ CopyMem (&IfInfo->HwAddress, &IpSb->SnpMode.CurrentAddress, IfInfo->HwAddressSize);\r
+}\r
+\r
+/**\r
+ The event handle routine when DHCPv4 process is finished or is updated.\r
+\r
+ @param[in] Event Not used.\r
+ @param[in] Context The pointer to the IP4 configuration instance data.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+Ip4Config2OnDhcp4Event (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ return ;\r
+}\r
+\r
+\r
+/**\r
+ Set the configuration for the EFI IPv4 network stack running on the communication\r
+ device this EFI_IP4_CONFIG2_PROTOCOL instance manages.\r
+\r
+ This function is used to set the configuration data of type DataType for the EFI\r
+ IPv4 network stack that is running on the communication device that this EFI IPv4\r
+ Configuration Protocol instance manages.\r
+\r
+ DataSize is used to calculate the count of structure instances in the Data for\r
+ a DataType in which multiple structure instances are allowed.\r
+\r
+ This function is always non-blocking. When setting some type of configuration data,\r
+ an asynchronous process is invoked to check the correctness of the data, such as\r
+ performing Duplicate Address Detection on the manually set local IPv4 addresses.\r
+ EFI_NOT_READY is returned immediately to indicate that such an asynchronous process\r
+ is invoked, and the process is not finished yet. The caller wanting to get the result\r
+ of the asynchronous process is required to call RegisterDataNotify() to register an\r
+ event on the specified configuration data. Once the event is signaled, the caller\r
+ can call GetData() to obtain the configuration data and know the result.\r
+ For other types of configuration data that do not require an asynchronous configuration\r
+ process, the result of the operation is immediately returned.\r
+\r
+ @param[in] This The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.\r
+ @param[in] DataType The type of data to set.\r
+ @param[in] DataSize Size of the buffer pointed to by Data in bytes.\r
+ @param[in] Data The data buffer to set. The type of the data buffer is\r
+ associated with the DataType.\r
+\r
+ @retval EFI_SUCCESS The specified configuration data for the EFI IPv6\r
+ network stack was set successfully.\r
+ @retval EFI_INVALID_PARAMETER One or more of the following are TRUE:\r
+ - This is NULL.\r
+ - Data is NULL.\r
+ - One or more fields in Data do not match the requirement of the\r
+ data type indicated by DataType.\r
+ @retval EFI_WRITE_PROTECTED The specified configuration data is read-only or the specified\r
+ configuration data cannot be set under the current policy.\r
+ @retval EFI_ACCESS_DENIED Another set operation on the specified configuration\r
+ data is already in process.\r
+ @retval EFI_NOT_READY An asynchronous process was invoked to set the specified\r
+ configuration data, and the process is not finished yet.\r
+ @retval EFI_BAD_BUFFER_SIZE The DataSize does not match the size of the type\r
+ indicated by DataType.\r
+ @retval EFI_UNSUPPORTED This DataType is not supported.\r
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
+ @retval EFI_DEVICE_ERROR An unexpected system error or network error occurred.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Config2SetData (\r
+ IN EFI_IP4_CONFIG2_PROTOCOL *This,\r
+ IN EFI_IP4_CONFIG2_DATA_TYPE DataType,\r
+ IN UINTN DataSize,\r
+ IN VOID *Data\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ IP4_CONFIG2_INSTANCE *Instance;\r
+ IP4_SERVICE *IpSb;\r
+\r
+ if ((This == NULL) || (Data == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataType >= Ip4Config2DataTypeMaximum) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+ NET_CHECK_SIGNATURE (IpSb, IP4_SERVICE_SIGNATURE);\r
+\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Status = Instance->DataItem[DataType].Status;\r
+ if (Status != EFI_NOT_READY) {\r
+\r
+ if (Instance->DataItem[DataType].SetData == NULL) {\r
+ //\r
+ // This type of data is readonly.\r
+ //\r
+ Status = EFI_WRITE_PROTECTED;\r
+ } else {\r
+\r
+ Status = Instance->DataItem[DataType].SetData (Instance, DataSize, Data);\r
+ if (!EFI_ERROR (Status)) {\r
+ //\r
+ // Fire up the events registered with this type of data.\r
+ //\r
+ NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);\r
+ Ip4Config2WriteConfigData (IpSb->MacString, Instance);\r
+ } else if (Status == EFI_ABORTED) {\r
+ //\r
+ // The SetData is aborted because the data to set is the same with\r
+ // the one maintained.\r
+ //\r
+ Status = EFI_SUCCESS;\r
+ NetMapIterate (&Instance->DataItem[DataType].EventMap, Ip4Config2SignalEvent, NULL);\r
+ }\r
+ }\r
+ } else {\r
+ //\r
+ // Another asynchornous process is on the way.\r
+ //\r
+ Status = EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get the configuration data for the EFI IPv4 network stack running on the communication\r
+ device that this EFI_IP4_CONFIG2_PROTOCOL instance manages.\r
+\r
+ This function returns the configuration data of type DataType for the EFI IPv4 network\r
+ stack running on the communication device that this EFI IPv4 Configuration Protocol instance\r
+ manages.\r
+\r
+ The caller is responsible for allocating the buffer used to return the specified\r
+ configuration data. The required size will be returned to the caller if the size of\r
+ the buffer is too small.\r
+\r
+ EFI_NOT_READY is returned if the specified configuration data is not ready due to an\r
+ asynchronous configuration process already in progress. The caller can call RegisterDataNotify()\r
+ to register an event on the specified configuration data. Once the asynchronous configuration\r
+ process is finished, the event will be signaled, and a subsequent GetData() call will return\r
+ the specified configuration data.\r
+\r
+ @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.\r
+ @param[in] DataType The type of data to get.\r
+ @param[in, out] DataSize On input, in bytes, the size of Data. On output, in bytes, the\r
+ size of buffer required to store the specified configuration data.\r
+ @param[in] Data The data buffer in which the configuration data is returned. The\r
+ type of the data buffer is associated with the DataType.\r
+ This is an optional parameter that may be NULL.\r
+\r
+ @retval EFI_SUCCESS The specified configuration data was obtained successfully.\r
+ @retval EFI_INVALID_PARAMETER One or more of the followings are TRUE:\r
+ - This is NULL.\r
+ - DataSize is NULL.\r
+ - Data is NULL if *DataSize is not zero.\r
+ @retval EFI_BUFFER_TOO_SMALL The size of Data is too small for the specified configuration data,\r
+ and the required size is returned in DataSize.\r
+ @retval EFI_NOT_READY The specified configuration data is not ready due to an\r
+ asynchronous configuration process already in progress.\r
+ @retval EFI_NOT_FOUND The specified configuration data is not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Config2GetData (\r
+ IN EFI_IP4_CONFIG2_PROTOCOL *This,\r
+ IN EFI_IP4_CONFIG2_DATA_TYPE DataType,\r
+ IN OUT UINTN *DataSize,\r
+ IN VOID *Data OPTIONAL\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ IP4_CONFIG2_INSTANCE *Instance;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+\r
+ if ((This == NULL) || (DataSize == NULL) || ((*DataSize != 0) && (Data == NULL))) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataType >= Ip4Config2DataTypeMaximum) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);\r
+ DataItem = &Instance->DataItem[DataType];\r
+\r
+ Status = Instance->DataItem[DataType].Status;\r
+ if (!EFI_ERROR (Status)) {\r
+\r
+ if (DataItem->GetData != NULL) {\r
+\r
+ Status = DataItem->GetData (Instance, DataSize, Data);\r
+ } else if (*DataSize < Instance->DataItem[DataType].DataSize) {\r
+ //\r
+ // Update the buffer length.\r
+ //\r
+ *DataSize = Instance->DataItem[DataType].DataSize;\r
+ Status = EFI_BUFFER_TOO_SMALL;\r
+ } else {\r
+\r
+ *DataSize = Instance->DataItem[DataType].DataSize;\r
+ CopyMem (Data, Instance->DataItem[DataType].Data.Ptr, *DataSize);\r
+ }\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Register an event that is signaled whenever a configuration process on the specified\r
+ configuration data is done.\r
+\r
+ This function registers an event that is to be signaled whenever a configuration\r
+ process on the specified configuration data is performed. An event can be registered\r
+ for a different DataType simultaneously. The caller is responsible for determining\r
+ which type of configuration data causes the signaling of the event in such an event.\r
+\r
+ @param[in] This Pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.\r
+ @param[in] DataType The type of data to unregister the event for.\r
+ @param[in] Event The event to register.\r
+\r
+ @retval EFI_SUCCESS The notification event for the specified configuration data is\r
+ registered.\r
+ @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
+ @retval EFI_UNSUPPORTED The configuration data type specified by DataType is not\r
+ supported.\r
+ @retval EFI_OUT_OF_RESOURCES Required system resources could not be allocated.\r
+ @retval EFI_ACCESS_DENIED The Event is already registered for the DataType.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Config2RegisterDataNotify (\r
+ IN EFI_IP4_CONFIG2_PROTOCOL *This,\r
+ IN EFI_IP4_CONFIG2_DATA_TYPE DataType,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ IP4_CONFIG2_INSTANCE *Instance;\r
+ NET_MAP *EventMap;\r
+ NET_MAP_ITEM *Item;\r
+\r
+ if ((This == NULL) || (Event == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataType >= Ip4Config2DataTypeMaximum) {\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);\r
+ EventMap = &Instance->DataItem[DataType].EventMap;\r
+\r
+ //\r
+ // Check whether this event is already registered for this DataType.\r
+ //\r
+ Item = NetMapFindKey (EventMap, Event);\r
+ if (Item == NULL) {\r
+\r
+ Status = NetMapInsertTail (EventMap, Event, NULL);\r
+\r
+ if (EFI_ERROR (Status)) {\r
+\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ } else {\r
+\r
+ Status = EFI_ACCESS_DENIED;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Remove a previously registered event for the specified configuration data.\r
+\r
+ @param This The pointer to the EFI_IP4_CONFIG2_PROTOCOL instance.\r
+ @param DataType The type of data to remove from the previously\r
+ registered event.\r
+ @param Event The event to be unregistered.\r
+\r
+ @retval EFI_SUCCESS The event registered for the specified\r
+ configuration data was removed.\r
+ @retval EFI_INVALID_PARAMETER This is NULL or Event is NULL.\r
+ @retval EFI_NOT_FOUND The Event has not been registered for the\r
+ specified DataType.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+EfiIp4Config2UnregisterDataNotify (\r
+ IN EFI_IP4_CONFIG2_PROTOCOL *This,\r
+ IN EFI_IP4_CONFIG2_DATA_TYPE DataType,\r
+ IN EFI_EVENT Event\r
+ )\r
+{\r
+ EFI_TPL OldTpl;\r
+ EFI_STATUS Status;\r
+ IP4_CONFIG2_INSTANCE *Instance;\r
+ NET_MAP_ITEM *Item;\r
+\r
+ if ((This == NULL) || (Event == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (DataType >= Ip4Config2DataTypeMaximum) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
+\r
+ Instance = IP4_CONFIG2_INSTANCE_FROM_PROTOCOL (This);\r
+\r
+ Item = NetMapFindKey (&Instance->DataItem[DataType].EventMap, Event);\r
+ if (Item != NULL) {\r
+\r
+ NetMapRemoveItem (&Instance->DataItem[DataType].EventMap, Item, NULL);\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+ gBS->RestoreTPL (OldTpl);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Initialize an IP4_CONFIG2_INSTANCE.\r
+\r
+ @param[out] Instance The buffer of IP4_CONFIG2_INSTANCE to be initialized.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources to complete the operation.\r
+ @retval EFI_SUCCESS The IP4_CONFIG2_INSTANCE initialized successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+Ip4Config2InitInstance (\r
+ OUT IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ IP4_SERVICE *IpSb;\r
+ IP4_CONFIG2_INSTANCE *TmpInstance;\r
+ LIST_ENTRY *Entry;\r
+ EFI_STATUS Status;\r
+ UINTN Index;\r
+ UINT16 IfIndex;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+\r
+\r
+ IpSb = IP4_SERVICE_FROM_IP4_CONFIG2_INSTANCE (Instance);\r
+\r
+ Instance->Signature = IP4_CONFIG2_INSTANCE_SIGNATURE;\r
+\r
+\r
+ //\r
+ // Determine the index of this interface.\r
+ //\r
+ IfIndex = 0;\r
+ NET_LIST_FOR_EACH (Entry, &mIp4Config2InstanceList) {\r
+ TmpInstance = NET_LIST_USER_STRUCT_S (Entry, IP4_CONFIG2_INSTANCE, Link, IP4_CONFIG2_INSTANCE_SIGNATURE);\r
+\r
+ if (TmpInstance->IfIndex > IfIndex) {\r
+ //\r
+ // There is a sequence hole because some interface is down.\r
+ //\r
+ break;\r
+ }\r
+\r
+ IfIndex++;\r
+ }\r
+\r
+ Instance->IfIndex = IfIndex;\r
+ NetListInsertBefore (Entry, &Instance->Link);\r
+\r
+ for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {\r
+ //\r
+ // Initialize the event map for each data item.\r
+ //\r
+ NetMapInit (&Instance->DataItem[Index].EventMap);\r
+ }\r
+\r
+ \r
+ //\r
+ // Initialize each data type: associate storage and set data size for the\r
+ // fixed size data types, hook the SetData function, set the data attribute.\r
+ //\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeInterfaceInfo];\r
+ DataItem->GetData = Ip4Config2GetIfInfo;\r
+ DataItem->Data.Ptr = &Instance->InterfaceInfo;\r
+ DataItem->DataSize = sizeof (Instance->InterfaceInfo);\r
+ SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED | DATA_ATTRIB_VOLATILE);\r
+ Ip4Config2InitIfInfo (IpSb, &Instance->InterfaceInfo);\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypePolicy];\r
+ DataItem->SetData = Ip4Config2SetPolicy;\r
+ DataItem->Data.Ptr = &Instance->Policy;\r
+ DataItem->DataSize = sizeof (Instance->Policy);\r
+ Instance->Policy = Ip4Config2PolicyDhcp;\r
+ SET_DATA_ATTRIB (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED);\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeManualAddress];\r
+ DataItem->SetData = Ip4Config2SetMaunualAddress;\r
+ DataItem->Status = EFI_NOT_FOUND;\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeGateway];\r
+ DataItem->SetData = Ip4Config2SetGateway;\r
+ DataItem->Status = EFI_NOT_FOUND;\r
+\r
+ DataItem = &Instance->DataItem[Ip4Config2DataTypeDnsServer];\r
+ DataItem->SetData = Ip4Config2SetDnsServer;\r
+ DataItem->Status = EFI_NOT_FOUND;\r
+\r
+ //\r
+ // Create the event used for DHCP.\r
+ //\r
+ Status = gBS->CreateEvent (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ Ip4Config2OnDhcp4Event,\r
+ Instance,\r
+ &Instance->Dhcp4Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ Instance->Configured = TRUE;\r
+\r
+ //\r
+ // Try to read the config data from NV variable.\r
+ //\r
+ Status = Ip4Config2ReadConfigData (IpSb->MacString, Instance);\r
+ if (Status == EFI_NOT_FOUND) {\r
+ Status = Ip4Config2WriteConfigData (IpSb->MacString, Instance);\r
+ }\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // Try to set the configured parameter.\r
+ //\r
+ for (Index = Ip4Config2DataTypePolicy; Index < Ip4Config2DataTypeMaximum; Index++) {\r
+ DataItem = &IpSb->Ip4Config2Instance.DataItem[Index];\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ DataItem->SetData (\r
+ &IpSb->Ip4Config2Instance,\r
+ DataItem->DataSize,\r
+ DataItem->Data.Ptr\r
+ );\r
+ }\r
+ }\r
+\r
+ Instance->Ip4Config2.SetData = EfiIp4Config2SetData;\r
+ Instance->Ip4Config2.GetData = EfiIp4Config2GetData;\r
+ Instance->Ip4Config2.RegisterDataNotify = EfiIp4Config2RegisterDataNotify;\r
+ Instance->Ip4Config2.UnregisterDataNotify = EfiIp4Config2UnregisterDataNotify;\r
+\r
+ //\r
+ // Publish the IP4 configuration form\r
+ //\r
+ return Ip4Config2FormInit (Instance);\r
+}\r
+\r
+\r
+/**\r
+ Release an IP4_CONFIG2_INSTANCE.\r
+\r
+ @param[in, out] Instance The buffer of IP4_CONFIG2_INSTANCE to be freed.\r
+\r
+**/\r
+VOID\r
+Ip4Config2CleanInstance (\r
+ IN OUT IP4_CONFIG2_INSTANCE *Instance\r
+ )\r
+{\r
+ UINTN Index;\r
+ IP4_CONFIG2_DATA_ITEM *DataItem;\r
+\r
+ if (Instance->DeclineAddress != NULL) {\r
+ FreePool (Instance->DeclineAddress);\r
+ }\r
+\r
+ if (!Instance->Configured) {\r
+ return ;\r
+ }\r
+\r
+ if (Instance->Dhcp4Handle != NULL) {\r
+\r
+ Ip4Config2DestroyDhcp4 (Instance);\r
+ }\r
+\r
+ //\r
+ // Close the event.\r
+ //\r
+ if (Instance->Dhcp4Event != NULL) {\r
+ gBS->CloseEvent (Instance->Dhcp4Event);\r
+ }\r
+\r
+ for (Index = 0; Index < Ip4Config2DataTypeMaximum; Index++) {\r
+\r
+ DataItem = &Instance->DataItem[Index];\r
+\r
+ if (!DATA_ATTRIB_SET (DataItem->Attribute, DATA_ATTRIB_SIZE_FIXED)) {\r
+ if (DataItem->Data.Ptr != NULL) {\r
+ FreePool (DataItem->Data.Ptr);\r
+ }\r
+ DataItem->Data.Ptr = NULL;\r
+ DataItem->DataSize = 0;\r
+ }\r
+\r
+ NetMapClean (&Instance->DataItem[Index].EventMap);\r
+ }\r
+\r
+ Ip4Config2FormUnload (Instance);\r
+\r
+ RemoveEntryList (&Instance->Link);\r
+}\r
+\r