REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			577 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			577 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   iSCSI DHCP4 related configuration routines.
 | |
| 
 | |
| Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "IScsiImpl.h"
 | |
| 
 | |
| /**
 | |
|   Extract the Root Path option and get the required target information.
 | |
| 
 | |
|   @param[in]        RootPath         The RootPath.
 | |
|   @param[in]        Length           Length of the RootPath option payload.
 | |
|   @param[in, out]   ConfigData       The iSCSI attempt configuration data read
 | |
|                                      from a nonvolatile device.
 | |
| 
 | |
|   @retval EFI_SUCCESS           All required information is extracted from the RootPath option.
 | |
|   @retval EFI_NOT_FOUND         The RootPath is not an iSCSI RootPath.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | |
|   @retval EFI_INVALID_PARAMETER The RootPath is malformatted.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IScsiDhcpExtractRootPath (
 | |
|   IN      CHAR8                        *RootPath,
 | |
|   IN      UINT8                        Length,
 | |
|   IN OUT  ISCSI_ATTEMPT_CONFIG_NVDATA  *ConfigData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   UINT8                        IScsiRootPathIdLen;
 | |
|   CHAR8                        *TmpStr;
 | |
|   ISCSI_ROOT_PATH_FIELD        Fields[RP_FIELD_IDX_MAX];
 | |
|   ISCSI_ROOT_PATH_FIELD        *Field;
 | |
|   UINT32                       FieldIndex;
 | |
|   UINT8                        Index;
 | |
|   ISCSI_SESSION_CONFIG_NVDATA  *ConfigNvData;
 | |
|   EFI_IP_ADDRESS               Ip;
 | |
|   UINT8                        IpMode;
 | |
| 
 | |
|   ConfigNvData = &ConfigData->SessionConfigData;
 | |
| 
 | |
|   //
 | |
|   // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>
 | |
|   //
 | |
|   IScsiRootPathIdLen = (UINT8)AsciiStrLen (ISCSI_ROOT_PATH_ID);
 | |
| 
 | |
|   if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Skip the iSCSI RootPath ID "iscsi:".
 | |
|   //
 | |
|   RootPath += IScsiRootPathIdLen;
 | |
|   Length    = (UINT8)(Length - IScsiRootPathIdLen);
 | |
| 
 | |
|   TmpStr = (CHAR8 *)AllocatePool (Length + 1);
 | |
|   if (TmpStr == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   CopyMem (TmpStr, RootPath, Length);
 | |
|   TmpStr[Length] = '\0';
 | |
| 
 | |
|   Index      = 0;
 | |
|   FieldIndex = RP_FIELD_IDX_SERVERNAME;
 | |
|   ZeroMem (&Fields[0], sizeof (Fields));
 | |
| 
 | |
|   //
 | |
|   // Extract the fields in the Root Path option string.
 | |
|   //
 | |
|   for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {
 | |
|     if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {
 | |
|       Fields[FieldIndex].Str = &TmpStr[Index];
 | |
|     }
 | |
| 
 | |
|     while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {
 | |
|       Index++;
 | |
|     }
 | |
| 
 | |
|     if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {
 | |
|       if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {
 | |
|         TmpStr[Index] = '\0';
 | |
|         Index++;
 | |
|       }
 | |
| 
 | |
|       if (Fields[FieldIndex].Str != NULL) {
 | |
|         Fields[FieldIndex].Len = (UINT8)AsciiStrLen (Fields[FieldIndex].Str);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (FieldIndex != RP_FIELD_IDX_MAX) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||
 | |
|       (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||
 | |
|       (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)
 | |
|       )
 | |
|   {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the IP address of the target.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_SERVERNAME];
 | |
| 
 | |
|   if (ConfigNvData->IpMode < IP_MODE_AUTOCONFIG) {
 | |
|     IpMode = ConfigNvData->IpMode;
 | |
|   } else {
 | |
|     IpMode = ConfigData->AutoConfigureMode;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Server name is expressed as domain name, just save it.
 | |
|   //
 | |
|   if ((!NET_IS_DIGIT (*(Field->Str))) && (*(Field->Str) != '[')) {
 | |
|     ConfigNvData->DnsMode = TRUE;
 | |
|     if ((Field->Len + 2) > sizeof (ConfigNvData->TargetUrl)) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     CopyMem (&ConfigNvData->TargetUrl, Field->Str, Field->Len);
 | |
|     ConfigNvData->TargetUrl[Field->Len + 1] = '\0';
 | |
|   } else {
 | |
|     ConfigNvData->DnsMode = FALSE;
 | |
|     ZeroMem (ConfigNvData->TargetUrl, sizeof (ConfigNvData->TargetUrl));
 | |
|     Status = IScsiAsciiStrToIp (Field->Str, IpMode, &Ip);
 | |
|     CopyMem (&ConfigNvData->TargetIp, &Ip, sizeof (EFI_IP_ADDRESS));
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Check the protocol type.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_PROTOCOL];
 | |
|   if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the port of the iSCSI target.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_PORT];
 | |
|   if (Field->Str != NULL) {
 | |
|     ConfigNvData->TargetPort = (UINT16)AsciiStrDecimalToUintn (Field->Str);
 | |
|   } else {
 | |
|     ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the LUN.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_LUN];
 | |
|   if (Field->Str != NULL) {
 | |
|     Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
|   } else {
 | |
|     ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the target iSCSI Name.
 | |
|   //
 | |
|   Field = &Fields[RP_FIELD_IDX_TARGETNAME];
 | |
| 
 | |
|   if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Validate the iSCSI name.
 | |
|   //
 | |
|   Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);
 | |
| 
 | |
| ON_EXIT:
 | |
| 
 | |
|   FreePool (TmpStr);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The callback function registered to the DHCP4 instance that is used to select
 | |
|   the qualified DHCP OFFER.
 | |
| 
 | |
|   @param[in]  This         The DHCP4 protocol.
 | |
|   @param[in]  Context      The context set when configuring the DHCP4 protocol.
 | |
|   @param[in]  CurrentState The current state of the DHCP4 protocol.
 | |
|   @param[in]  Dhcp4Event   The event occurs in the current state.
 | |
|   @param[in]  Packet       The DHCP packet that is to be sent or was already received.
 | |
|   @param[out] NewPacket    The packet used to replace the above Packet.
 | |
| 
 | |
|   @retval EFI_SUCCESS      Either the DHCP OFFER is qualified or we're not intereseted
 | |
|                            in the Dhcp4Event.
 | |
|   @retval EFI_NOT_READY    The DHCP OFFER packet doesn't match our requirements.
 | |
|   @retval Others           Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| IScsiDhcpSelectOffer (
 | |
|   IN  EFI_DHCP4_PROTOCOL  *This,
 | |
|   IN  VOID                *Context,
 | |
|   IN  EFI_DHCP4_STATE     CurrentState,
 | |
|   IN  EFI_DHCP4_EVENT     Dhcp4Event,
 | |
|   IN  EFI_DHCP4_PACKET    *Packet  OPTIONAL,
 | |
|   OUT EFI_DHCP4_PACKET    **NewPacket OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS               Status;
 | |
|   UINT32                   OptionCount;
 | |
|   EFI_DHCP4_PACKET_OPTION  **OptionList;
 | |
|   UINT32                   Index;
 | |
| 
 | |
|   if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   OptionCount = 0;
 | |
| 
 | |
|   Status = This->Parse (This, Packet, &OptionCount, NULL);
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
 | |
|   if (OptionList == NULL) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   Status = This->Parse (This, Packet, &OptionCount, OptionList);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool (OptionList);
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < OptionCount; Index++) {
 | |
|     if (OptionList[Index]->OpCode != DHCP4_TAG_ROOTPATH) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = IScsiDhcpExtractRootPath (
 | |
|                (CHAR8 *)&OptionList[Index]->Data[0],
 | |
|                OptionList[Index]->Length,
 | |
|                (ISCSI_ATTEMPT_CONFIG_NVDATA *)Context
 | |
|                );
 | |
| 
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   if (Index == OptionCount) {
 | |
|     Status = EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   FreePool (OptionList);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Parse the DHCP ACK to get the address configuration and DNS information.
 | |
| 
 | |
|   @param[in]       Dhcp4        The DHCP4 protocol.
 | |
|   @param[in, out]  ConfigData   The session configuration data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
 | |
|   @retval EFI_NO_MAPPING        DHCP failed to acquire address and other information.
 | |
|   @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is malformatted.
 | |
|   @retval EFI_DEVICE_ERROR      Other errors as indicated.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IScsiParseDhcpAck (
 | |
|   IN     EFI_DHCP4_PROTOCOL           *Dhcp4,
 | |
|   IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA  *ConfigData
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                   Status;
 | |
|   EFI_DHCP4_MODE_DATA          Dhcp4ModeData;
 | |
|   UINT32                       OptionCount;
 | |
|   EFI_DHCP4_PACKET_OPTION      **OptionList;
 | |
|   UINT32                       Index;
 | |
|   ISCSI_SESSION_CONFIG_NVDATA  *NvData;
 | |
| 
 | |
|   Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (Dhcp4ModeData.State != Dhcp4Bound) {
 | |
|     return EFI_NO_MAPPING;
 | |
|   }
 | |
| 
 | |
|   NvData = &ConfigData->SessionConfigData;
 | |
| 
 | |
|   CopyMem (&NvData->LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));
 | |
|   CopyMem (&NvData->SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));
 | |
|   CopyMem (&NvData->Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|   OptionCount = 0;
 | |
|   OptionList  = NULL;
 | |
| 
 | |
|   Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);
 | |
|   if (Status != EFI_BUFFER_TOO_SMALL) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));
 | |
|   if (OptionList == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreePool (OptionList);
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < OptionCount; Index++) {
 | |
|     //
 | |
|     // Get DNS server addresses and DHCP server address from this offer.
 | |
|     //
 | |
|     if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {
 | |
|       if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {
 | |
|         Status = EFI_INVALID_PARAMETER;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Primary DNS server address.
 | |
|       //
 | |
|       CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));
 | |
| 
 | |
|       if (OptionList[Index]->Length > 4) {
 | |
|         //
 | |
|         // Secondary DNS server address.
 | |
|         //
 | |
|         CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));
 | |
|       }
 | |
|     } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {
 | |
|       if (OptionList[Index]->Length != 4) {
 | |
|         Status = EFI_INVALID_PARAMETER;
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   FreePool (OptionList);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function will switch the IP4 configuration policy to Static.
 | |
| 
 | |
|   @param[in]  Ip4Config2          Pointer to the IP4 configuration protocol.
 | |
| 
 | |
|   @retval     EFI_SUCCESS         The policy is already configured to static.
 | |
|   @retval     Others              Other error as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IScsiSetIp4Policy (
 | |
|   IN EFI_IP4_CONFIG2_PROTOCOL  *Ip4Config2
 | |
|   )
 | |
| {
 | |
|   EFI_IP4_CONFIG2_POLICY  Policy;
 | |
|   EFI_STATUS              Status;
 | |
|   UINTN                   DataSize;
 | |
| 
 | |
|   DataSize = sizeof (EFI_IP4_CONFIG2_POLICY);
 | |
|   Status   = Ip4Config2->GetData (
 | |
|                            Ip4Config2,
 | |
|                            Ip4Config2DataTypePolicy,
 | |
|                            &DataSize,
 | |
|                            &Policy
 | |
|                            );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (Policy != Ip4Config2PolicyStatic) {
 | |
|     Policy = Ip4Config2PolicyStatic;
 | |
|     Status = Ip4Config2->SetData (
 | |
|                            Ip4Config2,
 | |
|                            Ip4Config2DataTypePolicy,
 | |
|                            sizeof (EFI_IP4_CONFIG2_POLICY),
 | |
|                            &Policy
 | |
|                            );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Parse the DHCP ACK to get the address configuration and DNS information.
 | |
| 
 | |
|   @param[in]       Image            The handle of the driver image.
 | |
|   @param[in]       Controller       The handle of the controller.
 | |
|   @param[in, out]  ConfigData       The attempt configuration data.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The DNS information is got from the DHCP ACK.
 | |
|   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | |
|   @retval EFI_NO_MEDIA          There was a media error.
 | |
|   @retval Others                Other errors as indicated.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| IScsiDoDhcp (
 | |
|   IN     EFI_HANDLE                   Image,
 | |
|   IN     EFI_HANDLE                   Controller,
 | |
|   IN OUT ISCSI_ATTEMPT_CONFIG_NVDATA  *ConfigData
 | |
|   )
 | |
| {
 | |
|   EFI_HANDLE                   Dhcp4Handle;
 | |
|   EFI_IP4_CONFIG2_PROTOCOL     *Ip4Config2;
 | |
|   EFI_DHCP4_PROTOCOL           *Dhcp4;
 | |
|   EFI_STATUS                   Status;
 | |
|   EFI_DHCP4_PACKET_OPTION      *ParaList;
 | |
|   EFI_DHCP4_CONFIG_DATA        Dhcp4ConfigData;
 | |
|   ISCSI_SESSION_CONFIG_NVDATA  *NvData;
 | |
|   EFI_STATUS                   MediaStatus;
 | |
| 
 | |
|   Dhcp4Handle = NULL;
 | |
|   Ip4Config2  = NULL;
 | |
|   Dhcp4       = NULL;
 | |
|   ParaList    = NULL;
 | |
| 
 | |
|   //
 | |
|   // Check media status before doing DHCP.
 | |
|   //
 | |
|   MediaStatus = EFI_SUCCESS;
 | |
|   NetLibDetectMediaWaitTimeout (Controller, ISCSI_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);
 | |
|   if (MediaStatus != EFI_SUCCESS) {
 | |
|     AsciiPrint ("\n  Error: Could not detect network connection.\n");
 | |
|     return EFI_NO_MEDIA;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // DHCP4 service allows only one of its children to be configured in
 | |
|   // the active state, If the DHCP4 D.O.R.A started by IP4 auto
 | |
|   // configuration and has not been completed, the Dhcp4 state machine
 | |
|   // will not be in the right state for the iSCSI to start a new round D.O.R.A.
 | |
|   // So, we need to switch its policy to static.
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (Controller, &gEfiIp4Config2ProtocolGuid, (VOID **)&Ip4Config2);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Status = IScsiSetIp4Policy (Ip4Config2);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create a DHCP4 child instance and get the protocol.
 | |
|   //
 | |
|   Status = NetLibCreateServiceChild (
 | |
|              Controller,
 | |
|              Image,
 | |
|              &gEfiDhcp4ServiceBindingProtocolGuid,
 | |
|              &Dhcp4Handle
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Dhcp4Handle,
 | |
|                   &gEfiDhcp4ProtocolGuid,
 | |
|                   (VOID **)&Dhcp4,
 | |
|                   Image,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   NvData = &ConfigData->SessionConfigData;
 | |
| 
 | |
|   ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);
 | |
|   if (ParaList == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Ask the server to reply with Netmask, Router, DNS, and RootPath options.
 | |
|   //
 | |
|   ParaList->OpCode  = DHCP4_TAG_PARA_LIST;
 | |
|   ParaList->Length  = (UINT8)(NvData->TargetInfoFromDhcp ? 4 : 3);
 | |
|   ParaList->Data[0] = DHCP4_TAG_NETMASK;
 | |
|   ParaList->Data[1] = DHCP4_TAG_ROUTER;
 | |
|   ParaList->Data[2] = DHCP4_TAG_DNS_SERVER;
 | |
|   ParaList->Data[3] = DHCP4_TAG_ROOTPATH;
 | |
| 
 | |
|   ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));
 | |
|   Dhcp4ConfigData.OptionCount = 1;
 | |
|   Dhcp4ConfigData.OptionList  = &ParaList;
 | |
| 
 | |
|   if (NvData->TargetInfoFromDhcp) {
 | |
|     //
 | |
|     // Use callback to select an offer that contains target information.
 | |
|     //
 | |
|     Dhcp4ConfigData.Dhcp4Callback   = IScsiDhcpSelectOffer;
 | |
|     Dhcp4ConfigData.CallbackContext = ConfigData;
 | |
|   }
 | |
| 
 | |
|   Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = Dhcp4->Start (Dhcp4, NULL);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Parse the ACK to get required information.
 | |
|   //
 | |
|   Status = IScsiParseDhcpAck (Dhcp4, ConfigData);
 | |
| 
 | |
| ON_EXIT:
 | |
| 
 | |
|   if (ParaList != NULL) {
 | |
|     FreePool (ParaList);
 | |
|   }
 | |
| 
 | |
|   if (Dhcp4 != NULL) {
 | |
|     Dhcp4->Stop (Dhcp4);
 | |
|     Dhcp4->Configure (Dhcp4, NULL);
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|            Dhcp4Handle,
 | |
|            &gEfiDhcp4ProtocolGuid,
 | |
|            Image,
 | |
|            Controller
 | |
|            );
 | |
|   }
 | |
| 
 | |
|   NetLibDestroyServiceChild (
 | |
|     Controller,
 | |
|     Image,
 | |
|     &gEfiDhcp4ServiceBindingProtocolGuid,
 | |
|     Dhcp4Handle
 | |
|     );
 | |
| 
 | |
|   return Status;
 | |
| }
 |