Mtftp6Option.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. /** @file
  2. Mtftp6 option parse functions implementation.
  3. Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Mtftp6Impl.h"
  7. CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = {
  8. "blksize",
  9. "windowsize",
  10. "timeout",
  11. "tsize",
  12. "multicast"
  13. };
  14. /**
  15. Parse the NULL terminated ASCII string of multicast option.
  16. @param[in] Str The pointer to the Ascii string of multicast option.
  17. @param[in] ExtInfo The pointer to the option information to be filled.
  18. @retval EFI_SUCCESS Parse the multicast option successfully.
  19. @retval EFI_INVALID_PARAMETER The string is malformatted.
  20. @retval EFI_OUT_OF_RESOURCES Failed to perform the operation due to lack of
  21. resources.
  22. **/
  23. EFI_STATUS
  24. Mtftp6ParseMcastOption (
  25. IN UINT8 *Str,
  26. IN MTFTP6_EXT_OPTION_INFO *ExtInfo
  27. )
  28. {
  29. EFI_STATUS Status;
  30. UINT32 Num;
  31. CHAR8 *Ip6Str;
  32. CHAR8 *TempStr;
  33. //
  34. // The multicast option is formatted like "addr,port,mc"
  35. // The server can also omit the ip and port, use ",,1"
  36. //
  37. if (*Str == ',') {
  38. ZeroMem (&ExtInfo->McastIp, sizeof (EFI_IPv6_ADDRESS));
  39. } else {
  40. Ip6Str = (CHAR8 *)AllocateCopyPool (AsciiStrSize ((CHAR8 *)Str), Str);
  41. if (Ip6Str == NULL) {
  42. return EFI_OUT_OF_RESOURCES;
  43. }
  44. //
  45. // The IPv6 address locates before comma in the input Str.
  46. //
  47. TempStr = Ip6Str;
  48. while ((*TempStr != '\0') && (*TempStr != ',')) {
  49. TempStr++;
  50. }
  51. *TempStr = '\0';
  52. Status = NetLibAsciiStrToIp6 (Ip6Str, &ExtInfo->McastIp);
  53. FreePool (Ip6Str);
  54. if (EFI_ERROR (Status)) {
  55. return Status;
  56. }
  57. while ((*Str != '\0') && (*Str != ',')) {
  58. Str++;
  59. }
  60. }
  61. if (*Str != ',') {
  62. return EFI_INVALID_PARAMETER;
  63. }
  64. Str++;
  65. //
  66. // Convert the port setting. the server can send us a port number or
  67. // empty string. such as the port in ",,1"
  68. //
  69. if (*Str == ',') {
  70. ExtInfo->McastPort = 0;
  71. } else {
  72. Num = (UINT32)AsciiStrDecimalToUintn ((CHAR8 *)Str);
  73. if (Num > 65535) {
  74. return EFI_INVALID_PARAMETER;
  75. }
  76. ExtInfo->McastPort = (UINT16)Num;
  77. while (NET_IS_DIGIT (*Str)) {
  78. Str++;
  79. }
  80. }
  81. if (*Str != ',') {
  82. return EFI_INVALID_PARAMETER;
  83. }
  84. Str++;
  85. //
  86. // Check the master/slave setting, 1 for master, 0 for slave.
  87. //
  88. Num = (UINT32)AsciiStrDecimalToUintn ((CHAR8 *)Str);
  89. if ((Num != 0) && (Num != 1)) {
  90. return EFI_INVALID_PARAMETER;
  91. }
  92. ExtInfo->IsMaster = (BOOLEAN)(Num == 1);
  93. while (NET_IS_DIGIT (*Str)) {
  94. Str++;
  95. }
  96. if (*Str != '\0') {
  97. return EFI_INVALID_PARAMETER;
  98. }
  99. return EFI_SUCCESS;
  100. }
  101. /**
  102. Parse the MTFTP6 extension options.
  103. @param[in] Options The pointer to the extension options list.
  104. @param[in] Count The num of the extension options.
  105. @param[in] IsRequest If FALSE, the extension options is included
  106. by a request packet.
  107. @param[in] Operation The current performed operation.
  108. @param[in] ExtInfo The pointer to the option information to be filled.
  109. @retval EFI_SUCCESS Parse the multicast option successfully.
  110. @retval EFI_INVALID_PARAMETER There is one option is malformatted at least.
  111. @retval EFI_UNSUPPORTED There is one option is not supported at least.
  112. **/
  113. EFI_STATUS
  114. Mtftp6ParseExtensionOption (
  115. IN EFI_MTFTP6_OPTION *Options,
  116. IN UINT32 Count,
  117. IN BOOLEAN IsRequest,
  118. IN UINT16 Operation,
  119. IN MTFTP6_EXT_OPTION_INFO *ExtInfo
  120. )
  121. {
  122. EFI_STATUS Status;
  123. EFI_MTFTP6_OPTION *Opt;
  124. UINT32 Index;
  125. UINT32 Value;
  126. ExtInfo->BitMap = 0;
  127. for (Index = 0; Index < Count; Index++) {
  128. Opt = Options + Index;
  129. if ((Opt->OptionStr == NULL) || (Opt->ValueStr == NULL)) {
  130. return EFI_INVALID_PARAMETER;
  131. }
  132. if (AsciiStriCmp ((CHAR8 *)Opt->OptionStr, "blksize") == 0) {
  133. //
  134. // block size option, valid value is between [8, 65464]
  135. //
  136. Value = (UINT32)AsciiStrDecimalToUintn ((CHAR8 *)Opt->ValueStr);
  137. if ((Value < 8) || (Value > 65464)) {
  138. return EFI_INVALID_PARAMETER;
  139. }
  140. ExtInfo->BlkSize = (UINT16)Value;
  141. ExtInfo->BitMap |= MTFTP6_OPT_BLKSIZE_BIT;
  142. } else if (AsciiStriCmp ((CHAR8 *)Opt->OptionStr, "timeout") == 0) {
  143. //
  144. // timeout option, valid value is between [1, 255]
  145. //
  146. Value = (UINT32)AsciiStrDecimalToUintn ((CHAR8 *)Opt->ValueStr);
  147. if ((Value < 1) || (Value > 255)) {
  148. return EFI_INVALID_PARAMETER;
  149. }
  150. ExtInfo->Timeout = (UINT8)Value;
  151. ExtInfo->BitMap |= MTFTP6_OPT_TIMEOUT_BIT;
  152. } else if (AsciiStriCmp ((CHAR8 *)Opt->OptionStr, "tsize") == 0) {
  153. //
  154. // tsize option, the biggest transfer supported is 4GB with block size option
  155. //
  156. ExtInfo->Tsize = (UINT32)AsciiStrDecimalToUintn ((CHAR8 *)Opt->ValueStr);
  157. ExtInfo->BitMap |= MTFTP6_OPT_TSIZE_BIT;
  158. } else if (AsciiStriCmp ((CHAR8 *)Opt->OptionStr, "multicast") == 0) {
  159. //
  160. // Multicast option, if it is a request, the value must be a zero string,
  161. // otherwise, it must be like "addr,port,mc" string, mc indicates master.
  162. //
  163. if (!IsRequest) {
  164. Status = Mtftp6ParseMcastOption (Opt->ValueStr, ExtInfo);
  165. if (EFI_ERROR (Status)) {
  166. return Status;
  167. }
  168. } else if (*(Opt->ValueStr) != '\0') {
  169. return EFI_INVALID_PARAMETER;
  170. }
  171. ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;
  172. } else if (AsciiStriCmp ((CHAR8 *)Opt->OptionStr, "windowsize") == 0) {
  173. if (Operation == EFI_MTFTP6_OPCODE_WRQ) {
  174. //
  175. // Currently, windowsize is not supported in the write operation.
  176. //
  177. return EFI_UNSUPPORTED;
  178. }
  179. Value = (UINT32)AsciiStrDecimalToUintn ((CHAR8 *)Opt->ValueStr);
  180. if ((Value < 1)) {
  181. return EFI_INVALID_PARAMETER;
  182. }
  183. ExtInfo->WindowSize = (UINT16)Value;
  184. ExtInfo->BitMap |= MTFTP6_OPT_WINDOWSIZE_BIT;
  185. } else if (IsRequest) {
  186. //
  187. // If it's a request, unsupported; else if it's a reply, ignore.
  188. //
  189. return EFI_UNSUPPORTED;
  190. }
  191. }
  192. return EFI_SUCCESS;
  193. }
  194. /**
  195. Go through the packet to fill the options array with the start
  196. addresses of each MTFTP option name/value pair.
  197. @param[in] Packet The packet to be checked.
  198. @param[in] PacketLen The length of the packet.
  199. @param[in, out] Count The num of the Options on input.
  200. The actual one on output.
  201. @param[in] Options The option array to be filled.
  202. It is optional.
  203. @retval EFI_SUCCESS The packet has been parsed successfully.
  204. @retval EFI_INVALID_PARAMETER The packet is malformatted.
  205. @retval EFI_BUFFER_TOO_SMALL The Options array is too small.
  206. @retval EFI_PROTOCOL_ERROR An unexpected MTFTPv6 packet was received.
  207. **/
  208. EFI_STATUS
  209. Mtftp6ParsePacketOption (
  210. IN EFI_MTFTP6_PACKET *Packet,
  211. IN UINT32 PacketLen,
  212. IN OUT UINT32 *Count,
  213. IN EFI_MTFTP6_OPTION *Options OPTIONAL
  214. )
  215. {
  216. UINT8 *Cur;
  217. UINT8 *Last;
  218. UINT8 Num;
  219. UINT8 *Name;
  220. UINT8 *Value;
  221. Num = 0;
  222. Cur = (UINT8 *)Packet + MTFTP6_OPCODE_LEN;
  223. Last = (UINT8 *)Packet + PacketLen - 1;
  224. //
  225. // process option name and value pairs.
  226. // The last byte is always zero.
  227. //
  228. while (Cur < Last) {
  229. Name = Cur;
  230. while (*Cur != 0) {
  231. Cur++;
  232. }
  233. if (Cur == Last) {
  234. return EFI_PROTOCOL_ERROR;
  235. }
  236. Value = ++Cur;
  237. while (*Cur != 0) {
  238. Cur++;
  239. }
  240. Num++;
  241. if ((Options != NULL) && (Num <= *Count)) {
  242. Options[Num - 1].OptionStr = Name;
  243. Options[Num - 1].ValueStr = Value;
  244. }
  245. Cur++;
  246. }
  247. //
  248. // Return buffer too small if the buffer passed-in isn't enough.
  249. //
  250. if ((*Count < Num) || (Options == NULL)) {
  251. *Count = Num;
  252. return EFI_BUFFER_TOO_SMALL;
  253. }
  254. *Count = Num;
  255. return EFI_SUCCESS;
  256. }
  257. /**
  258. Go through the packet, generate option list array and fill it
  259. by the result of parse options.
  260. @param[in] Packet The packet to be checked.
  261. @param[in] PacketLen The length of the packet.
  262. @param[in, out] OptionCount The num of the Options on input.
  263. The actual one on output.
  264. @param[out] OptionList The option list array to be generated
  265. and filled. It is optional.
  266. @retval EFI_SUCCESS The packet has been parsed successfully.
  267. @retval EFI_INVALID_PARAMETER The packet is malformatted.
  268. @retval EFI_PROTOCOL_ERROR There is one option is malformatted at least.
  269. @retval EFI_NOT_FOUND The packet has no options.
  270. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array.
  271. @retval EFI_BUFFER_TOO_SMALL The size of option list array is too small.
  272. **/
  273. EFI_STATUS
  274. Mtftp6ParseStart (
  275. IN EFI_MTFTP6_PACKET *Packet,
  276. IN UINT32 PacketLen,
  277. IN OUT UINT32 *OptionCount,
  278. OUT EFI_MTFTP6_OPTION **OptionList OPTIONAL
  279. )
  280. {
  281. EFI_STATUS Status;
  282. if ((PacketLen == 0) || (Packet == NULL) || (OptionCount == NULL)) {
  283. return EFI_INVALID_PARAMETER;
  284. }
  285. *OptionCount = 0;
  286. if (OptionList != NULL) {
  287. *OptionList = NULL;
  288. }
  289. if (NTOHS (Packet->OpCode) != EFI_MTFTP6_OPCODE_OACK) {
  290. return EFI_INVALID_PARAMETER;
  291. }
  292. //
  293. // The last byte must be zero to terminate the options.
  294. //
  295. if (*((UINT8 *)Packet + PacketLen - 1) != 0) {
  296. return EFI_PROTOCOL_ERROR;
  297. }
  298. //
  299. // Parse packet with NULL buffer for the first time to get the number
  300. // of options in the packet.
  301. //
  302. Status = Mtftp6ParsePacketOption (Packet, PacketLen, OptionCount, NULL);
  303. if (Status != EFI_BUFFER_TOO_SMALL) {
  304. return Status;
  305. }
  306. //
  307. // Return not found if there is no option parsed.
  308. //
  309. if (*OptionCount == 0) {
  310. return EFI_NOT_FOUND;
  311. }
  312. //
  313. // Only need parse out the number of options.
  314. //
  315. if (OptionList == NULL) {
  316. return EFI_SUCCESS;
  317. }
  318. //
  319. // Allocate the buffer according to the option number parsed before.
  320. //
  321. *OptionList = AllocateZeroPool (*OptionCount * sizeof (EFI_MTFTP6_OPTION));
  322. if (*OptionList == NULL) {
  323. return EFI_OUT_OF_RESOURCES;
  324. }
  325. //
  326. // Parse packet with allocated buffer for the second time to fill the pointer array
  327. // of the options in the packet.
  328. //
  329. Status = Mtftp6ParsePacketOption (Packet, PacketLen, OptionCount, *OptionList);
  330. if (EFI_ERROR (Status)) {
  331. return Status;
  332. }
  333. return EFI_SUCCESS;
  334. }