Mtftp4Option.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537
  1. /** @file
  2. Routines to process MTFTP4 options.
  3. Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
  4. SPDX-License-Identifier: BSD-2-Clause-Patent
  5. **/
  6. #include "Mtftp4Impl.h"
  7. CHAR8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {
  8. "blksize",
  9. "windowsize",
  10. "timeout",
  11. "tsize",
  12. "multicast"
  13. };
  14. /**
  15. Check whether two ascii strings are equal, ignore the case.
  16. @param Str1 The first ascii string
  17. @param Str2 The second ascii string
  18. @retval TRUE Two strings are equal when case is ignored.
  19. @retval FALSE Two strings are not equal.
  20. **/
  21. BOOLEAN
  22. NetStringEqualNoCase (
  23. IN UINT8 *Str1,
  24. IN UINT8 *Str2
  25. )
  26. {
  27. UINT8 Ch1;
  28. UINT8 Ch2;
  29. ASSERT ((Str1 != NULL) && (Str2 != NULL));
  30. for ( ; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {
  31. Ch1 = *Str1;
  32. Ch2 = *Str2;
  33. //
  34. // Convert them to lower case then compare two
  35. //
  36. if (('A' <= Ch1) && (Ch1 <= 'Z')) {
  37. Ch1 += 'a' - 'A';
  38. }
  39. if (('A' <= Ch2) && (Ch2 <= 'Z')) {
  40. Ch2 += 'a' - 'A';
  41. }
  42. if (Ch1 != Ch2) {
  43. return FALSE;
  44. }
  45. }
  46. return (BOOLEAN)(*Str1 == *Str2);
  47. }
  48. /**
  49. Convert a string to a UINT32 number.
  50. @param Str The string to convert from
  51. @return The number get from the string
  52. **/
  53. UINT32
  54. NetStringToU32 (
  55. IN UINT8 *Str
  56. )
  57. {
  58. UINT32 Num;
  59. ASSERT (Str != NULL);
  60. Num = 0;
  61. for ( ; NET_IS_DIGIT (*Str); Str++) {
  62. Num = Num * 10 + (*Str - '0');
  63. }
  64. return Num;
  65. }
  66. /**
  67. Convert a string of the format "192.168.0.1" to an IP address.
  68. @param Str The string representation of IP
  69. @param Ip The variable to get IP.
  70. @retval EFI_INVALID_PARAMETER The IP string is invalid.
  71. @retval EFI_SUCCESS The IP is parsed into the Ip
  72. **/
  73. EFI_STATUS
  74. NetStringToIp (
  75. IN UINT8 *Str,
  76. OUT IP4_ADDR *Ip
  77. )
  78. {
  79. UINT32 Byte;
  80. UINT32 Addr;
  81. UINTN Index;
  82. *Ip = 0;
  83. Addr = 0;
  84. for (Index = 0; Index < 4; Index++) {
  85. if (!NET_IS_DIGIT (*Str)) {
  86. return EFI_INVALID_PARAMETER;
  87. }
  88. Byte = NetStringToU32 (Str);
  89. if (Byte > 255) {
  90. return EFI_INVALID_PARAMETER;
  91. }
  92. Addr = (Addr << 8) | Byte;
  93. //
  94. // Skip all the digitals and check whether the separator is the dot
  95. //
  96. while (NET_IS_DIGIT (*Str)) {
  97. Str++;
  98. }
  99. if ((Index < 3) && (*Str != '.')) {
  100. return EFI_INVALID_PARAMETER;
  101. }
  102. Str++;
  103. }
  104. *Ip = Addr;
  105. return EFI_SUCCESS;
  106. }
  107. /**
  108. Go through the packet to fill the Options array with the start
  109. addresses of each MTFTP option name/value pair.
  110. @param Packet The packet to check
  111. @param PacketLen The packet's length
  112. @param Count The size of the Options on input. The actual
  113. options on output
  114. @param Options The option array to fill in
  115. @retval EFI_INVALID_PARAMETER The packet is malformatted
  116. @retval EFI_BUFFER_TOO_SMALL The Options array is too small
  117. @retval EFI_SUCCESS The packet has been parsed into the Options array.
  118. **/
  119. EFI_STATUS
  120. Mtftp4FillOptions (
  121. IN EFI_MTFTP4_PACKET *Packet,
  122. IN UINT32 PacketLen,
  123. IN OUT UINT32 *Count,
  124. OUT EFI_MTFTP4_OPTION *Options OPTIONAL
  125. )
  126. {
  127. UINT8 *Cur;
  128. UINT8 *Last;
  129. UINT8 Num;
  130. UINT8 *Name;
  131. UINT8 *Value;
  132. Num = 0;
  133. Cur = (UINT8 *)Packet + MTFTP4_OPCODE_LEN;
  134. Last = (UINT8 *)Packet + PacketLen - 1;
  135. //
  136. // process option name and value pairs. The last byte is always zero
  137. //
  138. while (Cur < Last) {
  139. Name = Cur;
  140. while (*Cur != 0) {
  141. Cur++;
  142. }
  143. if (Cur == Last) {
  144. return EFI_INVALID_PARAMETER;
  145. }
  146. Value = ++Cur;
  147. while (*Cur != 0) {
  148. Cur++;
  149. }
  150. Num++;
  151. if ((Options != NULL) && (Num <= *Count)) {
  152. Options[Num - 1].OptionStr = Name;
  153. Options[Num - 1].ValueStr = Value;
  154. }
  155. Cur++;
  156. }
  157. if ((*Count < Num) || (Options == NULL)) {
  158. *Count = Num;
  159. return EFI_BUFFER_TOO_SMALL;
  160. }
  161. *Count = Num;
  162. return EFI_SUCCESS;
  163. }
  164. /**
  165. Allocate and fill in a array of Mtftp options from the Packet.
  166. It first calls Mtftp4FillOption to get the option number, then allocate
  167. the array, at last, call Mtftp4FillOption again to save the options.
  168. @param Packet The packet to parse
  169. @param PacketLen The length of the packet
  170. @param OptionCount The number of options in the packet
  171. @param OptionList The point to get the option array.
  172. @retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a
  173. well-formatted OACK packet.
  174. @retval EFI_SUCCESS The option array is build
  175. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array
  176. **/
  177. EFI_STATUS
  178. Mtftp4ExtractOptions (
  179. IN EFI_MTFTP4_PACKET *Packet,
  180. IN UINT32 PacketLen,
  181. OUT UINT32 *OptionCount,
  182. OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL
  183. )
  184. {
  185. EFI_STATUS Status;
  186. *OptionCount = 0;
  187. if (OptionList != NULL) {
  188. *OptionList = NULL;
  189. }
  190. if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {
  191. return EFI_INVALID_PARAMETER;
  192. }
  193. if (PacketLen == MTFTP4_OPCODE_LEN) {
  194. return EFI_SUCCESS;
  195. }
  196. //
  197. // The last byte must be zero to terminate the options
  198. //
  199. if (*((UINT8 *)Packet + PacketLen - 1) != 0) {
  200. return EFI_INVALID_PARAMETER;
  201. }
  202. //
  203. // Get the number of options
  204. //
  205. Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);
  206. if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {
  207. return Status;
  208. }
  209. //
  210. // Allocate memory for the options, then call Mtftp4FillOptions to
  211. // fill it if caller want that.
  212. //
  213. if (OptionList == NULL) {
  214. return EFI_SUCCESS;
  215. }
  216. *OptionList = AllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));
  217. if (*OptionList == NULL) {
  218. return EFI_OUT_OF_RESOURCES;
  219. }
  220. Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);
  221. return EFI_SUCCESS;
  222. }
  223. /**
  224. Parse the MTFTP multicast option.
  225. @param Value The Mtftp multicast value string
  226. @param Option The option to save the info into.
  227. @retval EFI_INVALID_PARAMETER The multicast value string is invalid.
  228. @retval EFI_SUCCESS The multicast value is parsed into the Option
  229. **/
  230. EFI_STATUS
  231. Mtftp4ExtractMcast (
  232. IN UINT8 *Value,
  233. IN OUT MTFTP4_OPTION *Option
  234. )
  235. {
  236. EFI_STATUS Status;
  237. UINT32 Num;
  238. //
  239. // The multicast option is formatted like "204.0.0.1,1857,1"
  240. // The server can also omit the ip and port, use ",,1"
  241. //
  242. if (*Value == ',') {
  243. Option->McastIp = 0;
  244. } else {
  245. Status = NetStringToIp (Value, &Option->McastIp);
  246. if (EFI_ERROR (Status)) {
  247. return Status;
  248. }
  249. while ((*Value != 0) && (*Value != ',')) {
  250. Value++;
  251. }
  252. }
  253. if (*Value != ',') {
  254. return EFI_INVALID_PARAMETER;
  255. }
  256. Value++;
  257. //
  258. // Convert the port setting. the server can send us a port number or
  259. // empty string. such as the port in ",,1"
  260. //
  261. if (*Value == ',') {
  262. Option->McastPort = 0;
  263. } else {
  264. Num = NetStringToU32 (Value);
  265. if (Num > 65535) {
  266. return EFI_INVALID_PARAMETER;
  267. }
  268. Option->McastPort = (UINT16)Num;
  269. while (NET_IS_DIGIT (*Value)) {
  270. Value++;
  271. }
  272. }
  273. if (*Value != ',') {
  274. return EFI_INVALID_PARAMETER;
  275. }
  276. Value++;
  277. //
  278. // Check the master/slave setting, 1 for master, 0 for slave.
  279. //
  280. Num = NetStringToU32 (Value);
  281. if ((Num != 0) && (Num != 1)) {
  282. return EFI_INVALID_PARAMETER;
  283. }
  284. Option->Master = (BOOLEAN)(Num == 1);
  285. while (NET_IS_DIGIT (*Value)) {
  286. Value++;
  287. }
  288. if (*Value != '\0') {
  289. return EFI_INVALID_PARAMETER;
  290. }
  291. return EFI_SUCCESS;
  292. }
  293. /**
  294. Parse the option in Options array to MTFTP4_OPTION which program
  295. can access directly.
  296. @param Options The option array, which contains addresses of each
  297. option's name/value string.
  298. @param Count The number of options in the Options
  299. @param Request Whether this is a request or OACK. The format of
  300. multicast is different according to this setting.
  301. @param Operation The current performed operation.
  302. @param MtftpOption The MTFTP4_OPTION for easy access.
  303. @retval EFI_INVALID_PARAMETER The option is malformatted
  304. @retval EFI_UNSUPPORTED Some option isn't supported
  305. @retval EFI_SUCCESS The option are OK and has been parsed.
  306. **/
  307. EFI_STATUS
  308. Mtftp4ParseOption (
  309. IN EFI_MTFTP4_OPTION *Options,
  310. IN UINT32 Count,
  311. IN BOOLEAN Request,
  312. IN UINT16 Operation,
  313. OUT MTFTP4_OPTION *MtftpOption
  314. )
  315. {
  316. EFI_STATUS Status;
  317. UINT32 Index;
  318. UINT32 Value;
  319. EFI_MTFTP4_OPTION *This;
  320. MtftpOption->Exist = 0;
  321. for (Index = 0; Index < Count; Index++) {
  322. This = Options + Index;
  323. if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {
  324. return EFI_INVALID_PARAMETER;
  325. }
  326. if (NetStringEqualNoCase (This->OptionStr, (UINT8 *)"blksize")) {
  327. //
  328. // block size option, valid value is between [8, 65464]
  329. //
  330. Value = NetStringToU32 (This->ValueStr);
  331. if ((Value < 8) || (Value > 65464)) {
  332. return EFI_INVALID_PARAMETER;
  333. }
  334. MtftpOption->BlkSize = (UINT16)Value;
  335. MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;
  336. } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *)"timeout")) {
  337. //
  338. // timeout option, valid value is between [1, 255]
  339. //
  340. Value = NetStringToU32 (This->ValueStr);
  341. if ((Value < 1) || (Value > 255)) {
  342. return EFI_INVALID_PARAMETER;
  343. }
  344. MtftpOption->Timeout = (UINT8)Value;
  345. } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *)"tsize")) {
  346. //
  347. // tsize option, the biggest transfer supported is 4GB with block size option
  348. //
  349. MtftpOption->Tsize = NetStringToU32 (This->ValueStr);
  350. MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;
  351. } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *)"multicast")) {
  352. //
  353. // Multicast option, if it is a request, the value must be a zero
  354. // length string, otherwise, it is formatted like "204.0.0.1,1857,1\0"
  355. //
  356. if (Request) {
  357. if (*(This->ValueStr) != '\0') {
  358. return EFI_INVALID_PARAMETER;
  359. }
  360. } else {
  361. Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);
  362. if (EFI_ERROR (Status)) {
  363. return Status;
  364. }
  365. }
  366. MtftpOption->Exist |= MTFTP4_MCAST_EXIST;
  367. } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *)"windowsize")) {
  368. if (Operation == EFI_MTFTP4_OPCODE_WRQ) {
  369. //
  370. // Currently, windowsize is not supported in the write operation.
  371. //
  372. return EFI_UNSUPPORTED;
  373. }
  374. Value = NetStringToU32 (This->ValueStr);
  375. if (Value < 1) {
  376. return EFI_INVALID_PARAMETER;
  377. }
  378. MtftpOption->WindowSize = (UINT16)Value;
  379. MtftpOption->Exist |= MTFTP4_WINDOWSIZE_EXIST;
  380. } else if (Request) {
  381. //
  382. // Ignore the unsupported option if it is a reply, and return
  383. // EFI_UNSUPPORTED if it's a request according to the UEFI spec.
  384. //
  385. return EFI_UNSUPPORTED;
  386. }
  387. }
  388. return EFI_SUCCESS;
  389. }
  390. /**
  391. Parse the options in the OACK packet to MTFTP4_OPTION which program
  392. can access directly.
  393. @param Packet The OACK packet to parse
  394. @param PacketLen The length of the packet
  395. @param Operation The current performed operation.
  396. @param MtftpOption The MTFTP_OPTION for easy access.
  397. @retval EFI_INVALID_PARAMETER The packet option is malformatted
  398. @retval EFI_UNSUPPORTED Some option isn't supported
  399. @retval EFI_SUCCESS The option are OK and has been parsed.
  400. **/
  401. EFI_STATUS
  402. Mtftp4ParseOptionOack (
  403. IN EFI_MTFTP4_PACKET *Packet,
  404. IN UINT32 PacketLen,
  405. IN UINT16 Operation,
  406. OUT MTFTP4_OPTION *MtftpOption
  407. )
  408. {
  409. EFI_MTFTP4_OPTION *OptionList;
  410. EFI_STATUS Status;
  411. UINT32 Count;
  412. MtftpOption->Exist = 0;
  413. Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);
  414. if (EFI_ERROR (Status) || (Count == 0)) {
  415. return Status;
  416. }
  417. ASSERT (OptionList != NULL);
  418. Status = Mtftp4ParseOption (OptionList, Count, FALSE, Operation, MtftpOption);
  419. FreePool (OptionList);
  420. return Status;
  421. }