+++ /dev/null
-/** @file\r
- Routines to process MTFTP4 options.\r
-\r
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
-SPDX-License-Identifier: BSD-2-Clause-Patent\r
-\r
-**/\r
-\r
-#include "Mtftp4Impl.h"\r
-\r
-CHAR8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {\r
- "blksize",\r
- "windowsize",\r
- "timeout",\r
- "tsize",\r
- "multicast"\r
-};\r
-\r
-\r
-/**\r
- Check whether two ascii strings are equel, ignore the case.\r
-\r
- @param Str1 The first ascii string\r
- @param Str2 The second ascii string\r
-\r
- @retval TRUE Two strings are equal when case is ignored.\r
- @retval FALSE Two string are not equal.\r
-\r
-**/\r
-BOOLEAN\r
-NetStringEqualNoCase (\r
- IN UINT8 *Str1,\r
- IN UINT8 *Str2\r
- )\r
-{\r
- UINT8 Ch1;\r
- UINT8 Ch2;\r
-\r
- ASSERT ((Str1 != NULL) && (Str2 != NULL));\r
-\r
- for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {\r
- Ch1 = *Str1;\r
- Ch2 = *Str2;\r
-\r
- //\r
- // Convert them to lower case then compare two\r
- //\r
- if (('A' <= Ch1) && (Ch1 <= 'Z')) {\r
- Ch1 += 'a' - 'A';\r
- }\r
-\r
- if (('A' <= Ch2) && (Ch2 <= 'Z')) {\r
- Ch2 += 'a' - 'A';\r
- }\r
-\r
- if (Ch1 != Ch2) {\r
- return FALSE;\r
- }\r
- }\r
-\r
- return (BOOLEAN) (*Str1 == *Str2);\r
-}\r
-\r
-\r
-/**\r
- Convert a string to a UINT32 number.\r
-\r
- @param Str The string to convert from\r
-\r
- @return The number get from the string\r
-\r
-**/\r
-UINT32\r
-NetStringToU32 (\r
- IN UINT8 *Str\r
- )\r
-{\r
- UINT32 Num;\r
-\r
- ASSERT (Str != NULL);\r
-\r
- Num = 0;\r
-\r
- for (; NET_IS_DIGIT (*Str); Str++) {\r
- Num = Num * 10 + (*Str - '0');\r
- }\r
-\r
- return Num;\r
-}\r
-\r
-\r
-/**\r
- Convert a string of the format "192.168.0.1" to an IP address.\r
-\r
- @param Str The string representation of IP\r
- @param Ip The varible to get IP.\r
-\r
- @retval EFI_INVALID_PARAMETER The IP string is invalid.\r
- @retval EFI_SUCCESS The IP is parsed into the Ip\r
-\r
-**/\r
-EFI_STATUS\r
-NetStringToIp (\r
- IN UINT8 *Str,\r
- OUT IP4_ADDR *Ip\r
- )\r
-{\r
- UINT32 Byte;\r
- UINT32 Addr;\r
- UINTN Index;\r
-\r
- *Ip = 0;\r
- Addr = 0;\r
-\r
- for (Index = 0; Index < 4; Index++) {\r
- if (!NET_IS_DIGIT (*Str)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Byte = NetStringToU32 (Str);\r
-\r
- if (Byte > 255) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Addr = (Addr << 8) | Byte;\r
-\r
- //\r
- // Skip all the digitals and check whether the sepeator is the dot\r
- //\r
- while (NET_IS_DIGIT (*Str)) {\r
- Str++;\r
- }\r
-\r
- if ((Index < 3) && (*Str != '.')) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Str++;\r
- }\r
-\r
- *Ip = Addr;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Go through the packet to fill the Options array with the start\r
- addresses of each MTFTP option name/value pair.\r
-\r
- @param Packet The packet to check\r
- @param PacketLen The packet's length\r
- @param Count The size of the Options on input. The actual\r
- options on output\r
- @param Options The option array to fill in\r
-\r
- @retval EFI_INVALID_PARAMETER The packet is mal-formated\r
- @retval EFI_BUFFER_TOO_SMALL The Options array is too small\r
- @retval EFI_SUCCESS The packet has been parsed into the Options array.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4FillOptions (\r
- IN EFI_MTFTP4_PACKET *Packet,\r
- IN UINT32 PacketLen,\r
- IN OUT UINT32 *Count,\r
- OUT EFI_MTFTP4_OPTION *Options OPTIONAL\r
- )\r
-{\r
- UINT8 *Cur;\r
- UINT8 *Last;\r
- UINT8 Num;\r
- UINT8 *Name;\r
- UINT8 *Value;\r
-\r
- Num = 0;\r
- Cur = (UINT8 *) Packet + MTFTP4_OPCODE_LEN;\r
- Last = (UINT8 *) Packet + PacketLen - 1;\r
-\r
- //\r
- // process option name and value pairs. The last byte is always zero\r
- //\r
- while (Cur < Last) {\r
- Name = Cur;\r
-\r
- while (*Cur != 0) {\r
- Cur++;\r
- }\r
-\r
- if (Cur == Last) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Value = ++Cur;\r
-\r
- while (*Cur != 0) {\r
- Cur++;\r
- }\r
-\r
- Num++;\r
-\r
- if ((Options != NULL) && (Num <= *Count)) {\r
- Options[Num - 1].OptionStr = Name;\r
- Options[Num - 1].ValueStr = Value;\r
- }\r
-\r
- Cur++;\r
- }\r
-\r
- if ((*Count < Num) || (Options == NULL)) {\r
- *Count = Num;\r
- return EFI_BUFFER_TOO_SMALL;\r
- }\r
-\r
- *Count = Num;\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Allocate and fill in a array of Mtftp options from the Packet.\r
-\r
- It first calls Mtftp4FillOption to get the option number, then allocate\r
- the array, at last, call Mtftp4FillOption again to save the options.\r
-\r
- @param Packet The packet to parse\r
- @param PacketLen The length of the packet\r
- @param OptionCount The number of options in the packet\r
- @param OptionList The point to get the option array.\r
-\r
- @retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a\r
- well-formated OACK packet.\r
- @retval EFI_SUCCESS The option array is build\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4ExtractOptions (\r
- IN EFI_MTFTP4_PACKET *Packet,\r
- IN UINT32 PacketLen,\r
- OUT UINT32 *OptionCount,\r
- OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL\r
- )\r
-{\r
- EFI_STATUS Status;\r
-\r
- *OptionCount = 0;\r
-\r
- if (OptionList != NULL) {\r
- *OptionList = NULL;\r
- }\r
-\r
- if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (PacketLen == MTFTP4_OPCODE_LEN) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- //\r
- // The last byte must be zero to terminate the options\r
- //\r
- if (*((UINT8 *) Packet + PacketLen - 1) != 0) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- //\r
- // Get the number of options\r
- //\r
- Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);\r
-\r
- if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {\r
- return Status;\r
- }\r
-\r
- //\r
- // Allocate memory for the options, then call Mtftp4FillOptions to\r
- // fill it if caller want that.\r
- //\r
- if (OptionList == NULL) {\r
- return EFI_SUCCESS;\r
- }\r
-\r
- *OptionList = AllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));\r
-\r
- if (*OptionList == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Parse the MTFTP multicast option.\r
-\r
- @param Value The Mtftp multicast value string\r
- @param Option The option to save the info into.\r
-\r
- @retval EFI_INVALID_PARAMETER The multicast value string is invalid.\r
- @retval EFI_SUCCESS The multicast value is parsed into the Option\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4ExtractMcast (\r
- IN UINT8 *Value,\r
- IN OUT MTFTP4_OPTION *Option\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 Num;\r
-\r
- //\r
- // The multicast option is formated like "204.0.0.1,1857,1"\r
- // The server can also omit the ip and port, use ",,1"\r
- //\r
- if (*Value == ',') {\r
- Option->McastIp = 0;\r
- } else {\r
- Status = NetStringToIp (Value, &Option->McastIp);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- while ((*Value != 0) && (*Value != ',')) {\r
- Value++;\r
- }\r
- }\r
-\r
- if (*Value != ',') {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Value++;\r
-\r
- //\r
- // Convert the port setting. the server can send us a port number or\r
- // empty string. such as the port in ",,1"\r
- //\r
- if (*Value == ',') {\r
- Option->McastPort = 0;\r
- } else {\r
- Num = NetStringToU32 (Value);\r
-\r
- if (Num > 65535) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Option->McastPort = (UINT16) Num;\r
-\r
- while (NET_IS_DIGIT (*Value)) {\r
- Value++;\r
- }\r
- }\r
-\r
- if (*Value != ',') {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Value++;\r
-\r
- //\r
- // Check the master/slave setting, 1 for master, 0 for slave.\r
- //\r
- Num = NetStringToU32 (Value);\r
-\r
- if ((Num != 0) && (Num != 1)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Option->Master = (BOOLEAN) (Num == 1);\r
-\r
- while (NET_IS_DIGIT (*Value)) {\r
- Value++;\r
- }\r
-\r
- if (*Value != '\0') {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Parse the option in Options array to MTFTP4_OPTION which program\r
- can access directly.\r
-\r
- @param Options The option array, which contains addresses of each\r
- option's name/value string.\r
- @param Count The number of options in the Options\r
- @param Request Whether this is a request or OACK. The format of\r
- multicast is different according to this setting.\r
- @param Operation The current performed operation.\r
- @param MtftpOption The MTFTP4_OPTION for easy access.\r
-\r
- @retval EFI_INVALID_PARAMETER The option is mal-formated\r
- @retval EFI_UNSUPPORTED Some option isn't supported\r
- @retval EFI_SUCCESS The option are OK and has been parsed.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4ParseOption (\r
- IN EFI_MTFTP4_OPTION *Options,\r
- IN UINT32 Count,\r
- IN BOOLEAN Request,\r
- IN UINT16 Operation,\r
- OUT MTFTP4_OPTION *MtftpOption\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 Index;\r
- UINT32 Value;\r
- EFI_MTFTP4_OPTION *This;\r
-\r
- MtftpOption->Exist = 0;\r
-\r
- for (Index = 0; Index < Count; Index++) {\r
- This = Options + Index;\r
-\r
- if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "blksize")) {\r
- //\r
- // block size option, valid value is between [8, 65464]\r
- //\r
- Value = NetStringToU32 (This->ValueStr);\r
-\r
- if ((Value < 8) || (Value > 65464)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- MtftpOption->BlkSize = (UINT16) Value;\r
- MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;\r
-\r
- } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "timeout")) {\r
- //\r
- // timeout option, valid value is between [1, 255]\r
- //\r
- Value = NetStringToU32 (This->ValueStr);\r
-\r
- if ((Value < 1) || (Value > 255)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- MtftpOption->Timeout = (UINT8) Value;\r
-\r
- } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "tsize")) {\r
- //\r
- // tsize option, the biggest transfer supported is 4GB with block size option\r
- //\r
- MtftpOption->Tsize = NetStringToU32 (This->ValueStr);\r
- MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;\r
-\r
- } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "multicast")) {\r
- //\r
- // Multicast option, if it is a request, the value must be a zero\r
- // length string, otherwise, it is formated like "204.0.0.1,1857,1\0"\r
- //\r
- if (Request) {\r
- if (*(This->ValueStr) != '\0') {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- } else {\r
- Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);\r
-\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
- }\r
-\r
- MtftpOption->Exist |= MTFTP4_MCAST_EXIST;\r
-\r
- } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "windowsize")) {\r
- if (Operation == EFI_MTFTP4_OPCODE_WRQ) {\r
- //\r
- // Currently, windowsize is not supported in the write operation.\r
- //\r
- return EFI_UNSUPPORTED;\r
- }\r
-\r
- Value = NetStringToU32 (This->ValueStr);\r
-\r
- if (Value < 1) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- MtftpOption->WindowSize = (UINT16) Value;\r
- MtftpOption->Exist |= MTFTP4_WINDOWSIZE_EXIST;\r
- } else if (Request) {\r
- //\r
- // Ignore the unsupported option if it is a reply, and return\r
- // EFI_UNSUPPORTED if it's a request according to the UEFI spec.\r
- //\r
- return EFI_UNSUPPORTED;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Parse the options in the OACK packet to MTFTP4_OPTION which program\r
- can access directly.\r
-\r
- @param Packet The OACK packet to parse\r
- @param PacketLen The length of the packet\r
- @param Operation The current performed operation.\r
- @param MtftpOption The MTFTP_OPTION for easy access.\r
-\r
- @retval EFI_INVALID_PARAMETER The packet option is mal-formated\r
- @retval EFI_UNSUPPORTED Some option isn't supported\r
- @retval EFI_SUCCESS The option are OK and has been parsed.\r
-\r
-**/\r
-EFI_STATUS\r
-Mtftp4ParseOptionOack (\r
- IN EFI_MTFTP4_PACKET *Packet,\r
- IN UINT32 PacketLen,\r
- IN UINT16 Operation,\r
- OUT MTFTP4_OPTION *MtftpOption\r
- )\r
-{\r
- EFI_MTFTP4_OPTION *OptionList;\r
- EFI_STATUS Status;\r
- UINT32 Count;\r
-\r
- MtftpOption->Exist = 0;\r
-\r
- Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);\r
-\r
- if (EFI_ERROR (Status) || (Count == 0)) {\r
- return Status;\r
- }\r
- ASSERT (OptionList != NULL);\r
-\r
- Status = Mtftp4ParseOption (OptionList, Count, FALSE, Operation, MtftpOption);\r
-\r
- FreePool (OptionList);\r
- return Status;\r
-}\r