+++ /dev/null
-/** @file\r
- iSCSI DHCP related configuration routines.\r
-\r
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\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 "IScsiImpl.h"\r
-\r
-/**\r
- Extract the Root Path option and get the required target information.\r
-\r
- @param[in] RootPath The RootPath.\r
- @param[in] Length Length of the RootPath option payload.\r
- @param[in, out] ConfigNvData The iSCSI session configuration data read from nonvolatile device.\r
-\r
- @retval EFI_SUCCESS All required information is extracted from the RootPath option.\r
- @retval EFI_NOT_FOUND The RootPath is not an iSCSI RootPath.\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
- @retval EFI_INVALID_PARAMETER The RootPath is mal-formatted.\r
-**/\r
-EFI_STATUS\r
-IScsiDhcpExtractRootPath (\r
- IN CHAR8 *RootPath,\r
- IN UINT8 Length,\r
- IN OUT ISCSI_SESSION_CONFIG_NVDATA *ConfigNvData\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 IScsiRootPathIdLen;\r
- CHAR8 *TmpStr;\r
- ISCSI_ROOT_PATH_FIELD Fields[RP_FIELD_IDX_MAX];\r
- ISCSI_ROOT_PATH_FIELD *Field;\r
- UINT32 FieldIndex;\r
- UINT8 Index;\r
-\r
- //\r
- // "iscsi:"<servername>":"<protocol>":"<port>":"<LUN>":"<targetname>\r
- //\r
- IScsiRootPathIdLen = (UINT8) AsciiStrLen (ISCSI_ROOT_PATH_ID);\r
-\r
- if ((Length <= IScsiRootPathIdLen) || (CompareMem (RootPath, ISCSI_ROOT_PATH_ID, IScsiRootPathIdLen) != 0)) {\r
- return EFI_NOT_FOUND;\r
- }\r
- //\r
- // Skip the iSCSI RootPath ID "iscsi:".\r
- //\r
- RootPath += IScsiRootPathIdLen;\r
- Length = (UINT8) (Length - IScsiRootPathIdLen);\r
-\r
- TmpStr = (CHAR8 *) AllocatePool (Length + 1);\r
- if (TmpStr == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- CopyMem (TmpStr, RootPath, Length);\r
- TmpStr[Length] = '\0';\r
-\r
- Index = 0;\r
- FieldIndex = RP_FIELD_IDX_SERVERNAME;\r
- ZeroMem (&Fields[0], sizeof (Fields));\r
-\r
- //\r
- // Extract the fields in the Root Path option string.\r
- //\r
- for (FieldIndex = RP_FIELD_IDX_SERVERNAME; (FieldIndex < RP_FIELD_IDX_MAX) && (Index < Length); FieldIndex++) {\r
- if (TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
- Fields[FieldIndex].Str = &TmpStr[Index];\r
- }\r
-\r
- while ((TmpStr[Index] != ISCSI_ROOT_PATH_FIELD_DELIMITER) && (Index < Length)) {\r
- Index++;\r
- }\r
-\r
- if (TmpStr[Index] == ISCSI_ROOT_PATH_FIELD_DELIMITER) {\r
- if (FieldIndex != RP_FIELD_IDX_TARGETNAME) {\r
- TmpStr[Index] = '\0';\r
- Index++;\r
- }\r
-\r
- if (Fields[FieldIndex].Str != NULL) {\r
- Fields[FieldIndex].Len = (UINT8) AsciiStrLen (Fields[FieldIndex].Str);\r
- }\r
- }\r
- }\r
-\r
- if (FieldIndex != RP_FIELD_IDX_MAX) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
-\r
- if ((Fields[RP_FIELD_IDX_SERVERNAME].Str == NULL) ||\r
- (Fields[RP_FIELD_IDX_TARGETNAME].Str == NULL) ||\r
- (Fields[RP_FIELD_IDX_PROTOCOL].Len > 1)\r
- ) {\r
-\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Get the IP address of the target.\r
- //\r
- Field = &Fields[RP_FIELD_IDX_SERVERNAME];\r
- Status = IScsiAsciiStrToIp (Field->Str, &ConfigNvData->TargetIp);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Check the protocol type.\r
- //\r
- Field = &Fields[RP_FIELD_IDX_PROTOCOL];\r
- if ((Field->Str != NULL) && ((*(Field->Str) - '0') != EFI_IP_PROTO_TCP)) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Get the port of the iSCSI target.\r
- //\r
- Field = &Fields[RP_FIELD_IDX_PORT];\r
- if (Field->Str != NULL) {\r
- ConfigNvData->TargetPort = (UINT16) AsciiStrDecimalToUintn (Field->Str);\r
- } else {\r
- ConfigNvData->TargetPort = ISCSI_WELL_KNOWN_PORT;\r
- }\r
- //\r
- // Get the LUN.\r
- //\r
- Field = &Fields[RP_FIELD_IDX_LUN];\r
- if (Field->Str != NULL) {\r
- Status = IScsiAsciiStrToLun (Field->Str, ConfigNvData->BootLun);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- } else {\r
- ZeroMem (ConfigNvData->BootLun, sizeof (ConfigNvData->BootLun));\r
- }\r
- //\r
- // Get the target iSCSI Name.\r
- //\r
- Field = &Fields[RP_FIELD_IDX_TARGETNAME];\r
-\r
- if (AsciiStrLen (Field->Str) > ISCSI_NAME_MAX_SIZE - 1) {\r
- Status = EFI_INVALID_PARAMETER;\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Validate the iSCSI name.\r
- //\r
- Status = IScsiNormalizeName (Field->Str, AsciiStrLen (Field->Str));\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- AsciiStrCpyS (ConfigNvData->TargetName, ISCSI_NAME_MAX_SIZE, Field->Str);\r
-\r
-ON_EXIT:\r
-\r
- FreePool (TmpStr);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- The callback function registerd to the DHCP4 instance which is used to select\r
- the qualified DHCP OFFER.\r
-\r
- @param[in] This The DHCP4 protocol.\r
- @param[in] Context The context set when configuring the DHCP4 protocol.\r
- @param[in] CurrentState The current state of the DHCP4 protocol.\r
- @param[in] Dhcp4Event The event occurs in the current state.\r
- @param[in] Packet The DHCP packet that is to be sent or already received.\r
- @param[out] NewPacket The packet used to replace the above Packet.\r
-\r
- @retval EFI_SUCCESS Either the DHCP OFFER is qualified or we're not intereseted\r
- in the Dhcp4Event.\r
- @retval EFI_NOT_READY The DHCP OFFER packet doesn't match our requirements.\r
- @retval Others Other errors as indicated.\r
-**/\r
-EFI_STATUS\r
-EFIAPI\r
-IScsiDhcpSelectOffer (\r
- IN EFI_DHCP4_PROTOCOL * This,\r
- IN VOID *Context,\r
- IN EFI_DHCP4_STATE CurrentState,\r
- IN EFI_DHCP4_EVENT Dhcp4Event,\r
- IN EFI_DHCP4_PACKET * Packet, OPTIONAL\r
- OUT EFI_DHCP4_PACKET **NewPacket OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 OptionCount;\r
- EFI_DHCP4_PACKET_OPTION **OptionList;\r
- UINT32 Index;\r
-\r
- if ((Dhcp4Event != Dhcp4RcvdOffer) && (Dhcp4Event != Dhcp4SelectOffer)) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- OptionCount = 0;\r
-\r
- Status = This->Parse (This, Packet, &OptionCount, NULL);\r
- if (Status != EFI_BUFFER_TOO_SMALL) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
- if (OptionList == NULL) {\r
- return EFI_NOT_READY;\r
- }\r
-\r
- Status = This->Parse (This, Packet, &OptionCount, OptionList);\r
- if (EFI_ERROR (Status)) {\r
- FreePool (OptionList);\r
- return EFI_NOT_READY;\r
- }\r
-\r
- for (Index = 0; Index < OptionCount; Index++) {\r
- if (OptionList[Index]->OpCode != DHCP4_TAG_ROOTPATH) {\r
- continue;\r
- }\r
-\r
- Status = IScsiDhcpExtractRootPath (\r
- (CHAR8 *) &OptionList[Index]->Data[0],\r
- OptionList[Index]->Length,\r
- (ISCSI_SESSION_CONFIG_NVDATA *) Context\r
- );\r
-\r
- break;\r
- }\r
-\r
- if (Index == OptionCount) {\r
- Status = EFI_NOT_READY;\r
- }\r
-\r
- FreePool (OptionList);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Parse the DHCP ACK to get the address configuration and DNS information.\r
-\r
- @param[in] Dhcp4 The DHCP4 protocol.\r
- @param[in, out] ConfigData The session configuration data.\r
-\r
- @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
- @retval EFI_NO_MAPPING DHCP failed to acquire address and other information.\r
- @retval EFI_INVALID_PARAMETER The DHCP ACK's DNS option is mal-formatted.\r
- @retval EFI_DEVICE_ERROR Other errors as indicated.\r
-**/\r
-EFI_STATUS\r
-IScsiParseDhcpAck (\r
- IN EFI_DHCP4_PROTOCOL *Dhcp4,\r
- IN OUT ISCSI_SESSION_CONFIG_DATA *ConfigData\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_DHCP4_MODE_DATA Dhcp4ModeData;\r
- UINT32 OptionCount;\r
- EFI_DHCP4_PACKET_OPTION **OptionList;\r
- UINT32 Index;\r
-\r
- Status = Dhcp4->GetModeData (Dhcp4, &Dhcp4ModeData);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- if (Dhcp4ModeData.State != Dhcp4Bound) {\r
- return EFI_NO_MAPPING;\r
- }\r
-\r
- CopyMem (&ConfigData->NvData.LocalIp, &Dhcp4ModeData.ClientAddress, sizeof (EFI_IPv4_ADDRESS));\r
- CopyMem (&ConfigData->NvData.SubnetMask, &Dhcp4ModeData.SubnetMask, sizeof (EFI_IPv4_ADDRESS));\r
- CopyMem (&ConfigData->NvData.Gateway, &Dhcp4ModeData.RouterAddress, sizeof (EFI_IPv4_ADDRESS));\r
-\r
- OptionCount = 0;\r
- OptionList = NULL;\r
-\r
- Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
- if (Status != EFI_BUFFER_TOO_SMALL) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- OptionList = AllocatePool (OptionCount * sizeof (EFI_DHCP4_PACKET_OPTION *));\r
- if (OptionList == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Status = Dhcp4->Parse (Dhcp4, Dhcp4ModeData.ReplyPacket, &OptionCount, OptionList);\r
- if (EFI_ERROR (Status)) {\r
- FreePool (OptionList);\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- for (Index = 0; Index < OptionCount; Index++) {\r
- //\r
- // Get DNS server addresses and DHCP server address from this offer.\r
- //\r
- if (OptionList[Index]->OpCode == DHCP4_TAG_DNS_SERVER) {\r
-\r
- if (((OptionList[Index]->Length & 0x3) != 0) || (OptionList[Index]->Length == 0)) {\r
- Status = EFI_INVALID_PARAMETER;\r
- break;\r
- }\r
- //\r
- // Primary DNS server address.\r
- //\r
- CopyMem (&ConfigData->PrimaryDns, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
-\r
- if (OptionList[Index]->Length > 4) {\r
- //\r
- // Secondary DNS server address\r
- //\r
- CopyMem (&ConfigData->SecondaryDns, &OptionList[Index]->Data[4], sizeof (EFI_IPv4_ADDRESS));\r
- }\r
- } else if (OptionList[Index]->OpCode == DHCP4_TAG_SERVER_ID) {\r
- if (OptionList[Index]->Length != 4) {\r
- Status = EFI_INVALID_PARAMETER;\r
- break;\r
- }\r
-\r
- CopyMem (&ConfigData->DhcpServer, &OptionList[Index]->Data[0], sizeof (EFI_IPv4_ADDRESS));\r
- }\r
- }\r
-\r
- FreePool (OptionList);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Parse the DHCP ACK to get the address configuration and DNS information.\r
-\r
- @param[in] Image The handle of the driver image.\r
- @param[in] Controller The handle of the controller;\r
- @param[in, out] ConfigData The session configuration data.\r
-\r
- @retval EFI_SUCCESS The DNS information is got from the DHCP ACK.\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
- @retval EFI_NO_MEDIA There was a media error.\r
- @retval Others Other errors as indicated.\r
-\r
-**/\r
-EFI_STATUS\r
-IScsiDoDhcp (\r
- IN EFI_HANDLE Image,\r
- IN EFI_HANDLE Controller,\r
- IN OUT ISCSI_SESSION_CONFIG_DATA *ConfigData\r
- )\r
-{\r
- EFI_HANDLE Dhcp4Handle;\r
- EFI_DHCP4_PROTOCOL *Dhcp4;\r
- EFI_STATUS Status;\r
- EFI_DHCP4_PACKET_OPTION *ParaList;\r
- EFI_DHCP4_CONFIG_DATA Dhcp4ConfigData;\r
- EFI_STATUS MediaStatus;\r
- UINT8 *Data;\r
-\r
- Dhcp4Handle = NULL;\r
- Dhcp4 = NULL;\r
- ParaList = NULL;\r
-\r
- //\r
- // Check media status before do DHCP\r
- //\r
- MediaStatus = EFI_SUCCESS;\r
- NetLibDetectMediaWaitTimeout (Controller, ISCSI_CHECK_MEDIA_GET_DHCP_WAITING_TIME, &MediaStatus);\r
- if (MediaStatus != EFI_SUCCESS) {\r
- return EFI_NO_MEDIA;\r
- }\r
-\r
- //\r
- // Create a DHCP4 child instance and get the protocol.\r
- //\r
- Status = NetLibCreateServiceChild (\r
- Controller,\r
- Image,\r
- &gEfiDhcp4ServiceBindingProtocolGuid,\r
- &Dhcp4Handle\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- Status = gBS->OpenProtocol (\r
- Dhcp4Handle,\r
- &gEfiDhcp4ProtocolGuid,\r
- (VOID **)&Dhcp4,\r
- Image,\r
- Controller,\r
- EFI_OPEN_PROTOCOL_BY_DRIVER\r
- );\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- ParaList = AllocatePool (sizeof (EFI_DHCP4_PACKET_OPTION) + 3);\r
- if (ParaList == NULL) {\r
- Status = EFI_OUT_OF_RESOURCES;\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Ask the server to reply with Netmask, Router, DNS and RootPath options.\r
- //\r
- ParaList->OpCode = DHCP4_TAG_PARA_LIST;\r
- ParaList->Length = (UINT8) (ConfigData->NvData.TargetInfoFromDhcp ? 4 : 3);\r
- Data = &ParaList->Data[0];\r
- Data[0] = DHCP4_TAG_NETMASK;\r
- Data[1] = DHCP4_TAG_ROUTER;\r
- Data[2] = DHCP4_TAG_DNS_SERVER;\r
- Data[3] = DHCP4_TAG_ROOTPATH;\r
-\r
- ZeroMem (&Dhcp4ConfigData, sizeof (EFI_DHCP4_CONFIG_DATA));\r
- Dhcp4ConfigData.OptionCount = 1;\r
- Dhcp4ConfigData.OptionList = &ParaList;\r
-\r
- if (ConfigData->NvData.TargetInfoFromDhcp) {\r
- //\r
- // Use callback to select an offer which contains target information.\r
- //\r
- Dhcp4ConfigData.Dhcp4Callback = IScsiDhcpSelectOffer;\r
- Dhcp4ConfigData.CallbackContext = &ConfigData->NvData;\r
- }\r
-\r
- Status = Dhcp4->Configure (Dhcp4, &Dhcp4ConfigData);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
-\r
- Status = Dhcp4->Start (Dhcp4, NULL);\r
- if (EFI_ERROR (Status)) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Parse the ACK to get required information.\r
- //\r
- Status = IScsiParseDhcpAck (Dhcp4, ConfigData);\r
-\r
-ON_EXIT:\r
-\r
- if (ParaList != NULL) {\r
- FreePool (ParaList);\r
- }\r
-\r
- if (Dhcp4 != NULL) {\r
- Dhcp4->Stop (Dhcp4);\r
- Dhcp4->Configure (Dhcp4, NULL);\r
-\r
- gBS->CloseProtocol (\r
- Dhcp4Handle,\r
- &gEfiDhcp4ProtocolGuid,\r
- Image,\r
- Controller\r
- );\r
- }\r
-\r
- NetLibDestroyServiceChild (\r
- Controller,\r
- Image,\r
- &gEfiDhcp4ServiceBindingProtocolGuid,\r
- Dhcp4Handle\r
- );\r
-\r
- return Status;\r
-}\r