]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/Mtftp4Dxe/Mtftp4Option.c
MdeModulePke/Mtftp4Dxe: Support windowsize in read request operation.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / Mtftp4Dxe / Mtftp4Option.c
CommitLineData
772db4bb 1/** @file\r
dab714aa 2 Routines to process MTFTP4 options.\r
e2851998 3\r
6c047cfa 4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 5This program and the accompanying materials\r
772db4bb 6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
dab714aa 8http://opensource.org/licenses/bsd-license.php<BR>\r
772db4bb 9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
772db4bb 13**/\r
14\r
15#include "Mtftp4Impl.h"\r
16\r
67a58d0f 17CHAR8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {\r
772db4bb 18 "blksize",\r
6c047cfa 19 "windowsize",\r
772db4bb 20 "timeout",\r
21 "tsize",\r
22 "multicast"\r
23};\r
24\r
25\r
3dc3861a 26/**\r
27 Check whether two ascii strings are equel, ignore the case.\r
28\r
29 @param Str1 The first ascii string\r
30 @param Str2 The second ascii string\r
31\r
32 @retval TRUE Two strings are equal when case is ignored.\r
33 @retval FALSE Two string are not equal.\r
34\r
35**/\r
36BOOLEAN\r
37NetStringEqualNoCase (\r
38 IN UINT8 *Str1,\r
39 IN UINT8 *Str2\r
40 )\r
41{\r
42 UINT8 Ch1;\r
43 UINT8 Ch2;\r
44\r
45 ASSERT ((Str1 != NULL) && (Str2 != NULL));\r
46\r
47 for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {\r
48 Ch1 = *Str1;\r
49 Ch2 = *Str2;\r
50\r
51 //\r
52 // Convert them to lower case then compare two\r
53 //\r
54 if (('A' <= Ch1) && (Ch1 <= 'Z')) {\r
55 Ch1 += 'a' - 'A';\r
56 }\r
57\r
58 if (('A' <= Ch2) && (Ch2 <= 'Z')) {\r
59 Ch2 += 'a' - 'A';\r
60 }\r
61\r
62 if (Ch1 != Ch2) {\r
63 return FALSE;\r
64 }\r
65 }\r
66\r
67 return (BOOLEAN) (*Str1 == *Str2);\r
68}\r
69\r
70\r
71/**\r
72 Convert a string to a UINT32 number.\r
73\r
74 @param Str The string to convert from\r
75\r
76 @return The number get from the string\r
77\r
78**/\r
79UINT32\r
80NetStringToU32 (\r
81 IN UINT8 *Str\r
82 )\r
83{\r
84 UINT32 Num;\r
85\r
86 ASSERT (Str != NULL);\r
87\r
88 Num = 0;\r
89\r
90 for (; NET_IS_DIGIT (*Str); Str++) {\r
91 Num = Num * 10 + (*Str - '0');\r
92 }\r
93\r
94 return Num;\r
95}\r
96\r
97\r
98/**\r
99 Convert a string of the format "192.168.0.1" to an IP address.\r
100\r
101 @param Str The string representation of IP\r
102 @param Ip The varible to get IP.\r
103\r
104 @retval EFI_INVALID_PARAMETER The IP string is invalid.\r
105 @retval EFI_SUCCESS The IP is parsed into the Ip\r
106\r
107**/\r
108EFI_STATUS\r
109NetStringToIp (\r
110 IN UINT8 *Str,\r
111 OUT IP4_ADDR *Ip\r
112 )\r
113{\r
114 UINT32 Byte;\r
115 UINT32 Addr;\r
116 UINTN Index;\r
117\r
118 *Ip = 0;\r
119 Addr = 0;\r
120\r
121 for (Index = 0; Index < 4; Index++) {\r
122 if (!NET_IS_DIGIT (*Str)) {\r
123 return EFI_INVALID_PARAMETER;\r
124 }\r
125\r
126 Byte = NetStringToU32 (Str);\r
127\r
128 if (Byte > 255) {\r
129 return EFI_INVALID_PARAMETER;\r
130 }\r
131\r
132 Addr = (Addr << 8) | Byte;\r
133\r
134 //\r
135 // Skip all the digitals and check whether the sepeator is the dot\r
136 //\r
137 while (NET_IS_DIGIT (*Str)) {\r
138 Str++;\r
139 }\r
140\r
141 if ((Index < 3) && (*Str != '.')) {\r
142 return EFI_INVALID_PARAMETER;\r
143 }\r
144\r
145 Str++;\r
146 }\r
147\r
148 *Ip = Addr;\r
149\r
150 return EFI_SUCCESS;\r
151}\r
152\r
153\r
772db4bb 154/**\r
155 Go through the packet to fill the Options array with the start\r
156 addresses of each MTFTP option name/value pair.\r
157\r
158 @param Packet The packet to check\r
159 @param PacketLen The packet's length\r
160 @param Count The size of the Options on input. The actual\r
161 options on output\r
162 @param Options The option array to fill in\r
163\r
164 @retval EFI_INVALID_PARAMETER The packet is mal-formated\r
165 @retval EFI_BUFFER_TOO_SMALL The Options array is too small\r
166 @retval EFI_SUCCESS The packet has been parsed into the Options array.\r
167\r
168**/\r
772db4bb 169EFI_STATUS\r
170Mtftp4FillOptions (\r
dab714aa 171 IN EFI_MTFTP4_PACKET *Packet,\r
172 IN UINT32 PacketLen,\r
173 IN OUT UINT32 *Count,\r
174 OUT EFI_MTFTP4_OPTION *Options OPTIONAL\r
772db4bb 175 )\r
176{\r
177 UINT8 *Cur;\r
178 UINT8 *Last;\r
179 UINT8 Num;\r
180 UINT8 *Name;\r
181 UINT8 *Value;\r
182\r
183 Num = 0;\r
184 Cur = (UINT8 *) Packet + MTFTP4_OPCODE_LEN;\r
185 Last = (UINT8 *) Packet + PacketLen - 1;\r
186\r
187 //\r
188 // process option name and value pairs. The last byte is always zero\r
189 //\r
190 while (Cur < Last) {\r
191 Name = Cur;\r
192\r
193 while (*Cur != 0) {\r
194 Cur++;\r
195 }\r
196\r
197 if (Cur == Last) {\r
198 return EFI_INVALID_PARAMETER;\r
199 }\r
200\r
201 Value = ++Cur;\r
202\r
203 while (*Cur != 0) {\r
204 Cur++;\r
205 }\r
206\r
207 Num++;\r
208\r
209 if ((Options != NULL) && (Num <= *Count)) {\r
210 Options[Num - 1].OptionStr = Name;\r
211 Options[Num - 1].ValueStr = Value;\r
212 }\r
213\r
214 Cur++;\r
215 }\r
216\r
217 if ((*Count < Num) || (Options == NULL)) {\r
218 *Count = Num;\r
219 return EFI_BUFFER_TOO_SMALL;\r
220 }\r
221\r
222 *Count = Num;\r
223 return EFI_SUCCESS;\r
224}\r
225\r
226\r
227/**\r
e2851998 228 Allocate and fill in a array of Mtftp options from the Packet.\r
229\r
dab714aa 230 It first calls Mtftp4FillOption to get the option number, then allocate\r
772db4bb 231 the array, at last, call Mtftp4FillOption again to save the options.\r
232\r
233 @param Packet The packet to parse\r
234 @param PacketLen The length of the packet\r
235 @param OptionCount The number of options in the packet\r
236 @param OptionList The point to get the option array.\r
237\r
238 @retval EFI_INVALID_PARAMETER The parametera are invalid or packet isn't a\r
239 well-formated OACK packet.\r
240 @retval EFI_SUCCESS The option array is build\r
241 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the array\r
242\r
243**/\r
244EFI_STATUS\r
245Mtftp4ExtractOptions (\r
dab714aa 246 IN EFI_MTFTP4_PACKET *Packet,\r
247 IN UINT32 PacketLen,\r
248 OUT UINT32 *OptionCount,\r
249 OUT EFI_MTFTP4_OPTION **OptionList OPTIONAL\r
772db4bb 250 )\r
251{\r
252 EFI_STATUS Status;\r
253\r
254 *OptionCount = 0;\r
255\r
256 if (OptionList != NULL) {\r
257 *OptionList = NULL;\r
258 }\r
259\r
260 if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {\r
261 return EFI_INVALID_PARAMETER;\r
262 }\r
263\r
264 if (PacketLen == MTFTP4_OPCODE_LEN) {\r
265 return EFI_SUCCESS;\r
266 }\r
267\r
268 //\r
269 // The last byte must be zero to terminate the options\r
270 //\r
271 if (*((UINT8 *) Packet + PacketLen - 1) != 0) {\r
272 return EFI_INVALID_PARAMETER;\r
273 }\r
274\r
275 //\r
276 // Get the number of options\r
277 //\r
278 Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);\r
279\r
280 if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {\r
281 return Status;\r
282 }\r
283\r
284 //\r
285 // Allocate memory for the options, then call Mtftp4FillOptions to\r
286 // fill it if caller want that.\r
287 //\r
288 if (OptionList == NULL) {\r
289 return EFI_SUCCESS;\r
290 }\r
291\r
e48e37fc 292 *OptionList = AllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));\r
772db4bb 293\r
294 if (*OptionList == NULL) {\r
295 return EFI_OUT_OF_RESOURCES;\r
296 }\r
297\r
298 Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);\r
299 return EFI_SUCCESS;\r
300}\r
301\r
302\r
772db4bb 303/**\r
304 Parse the MTFTP multicast option.\r
305\r
306 @param Value The Mtftp multicast value string\r
307 @param Option The option to save the info into.\r
308\r
309 @retval EFI_INVALID_PARAMETER The multicast value string is invalid.\r
310 @retval EFI_SUCCESS The multicast value is parsed into the Option\r
311\r
312**/\r
772db4bb 313EFI_STATUS\r
314Mtftp4ExtractMcast (\r
dab714aa 315 IN UINT8 *Value,\r
316 IN OUT MTFTP4_OPTION *Option\r
772db4bb 317 )\r
318{\r
319 EFI_STATUS Status;\r
320 UINT32 Num;\r
321\r
322 //\r
323 // The multicast option is formated like "204.0.0.1,1857,1"\r
324 // The server can also omit the ip and port, use ",,1"\r
325 //\r
326 if (*Value == ',') {\r
327 Option->McastIp = 0;\r
328 } else {\r
329 Status = NetStringToIp (Value, &Option->McastIp);\r
330\r
331 if (EFI_ERROR (Status)) {\r
332 return Status;\r
333 }\r
334\r
dab714aa 335 while ((*Value != 0) && (*Value != ',')) {\r
772db4bb 336 Value++;\r
337 }\r
338 }\r
339\r
340 if (*Value != ',') {\r
341 return EFI_INVALID_PARAMETER;\r
342 }\r
343\r
344 Value++;\r
345\r
346 //\r
347 // Convert the port setting. the server can send us a port number or\r
348 // empty string. such as the port in ",,1"\r
349 //\r
350 if (*Value == ',') {\r
351 Option->McastPort = 0;\r
352 } else {\r
353 Num = NetStringToU32 (Value);\r
354\r
355 if (Num > 65535) {\r
356 return EFI_INVALID_PARAMETER;\r
357 }\r
358\r
dab714aa 359 Option->McastPort = (UINT16) Num;\r
772db4bb 360\r
361 while (NET_IS_DIGIT (*Value)) {\r
362 Value++;\r
363 }\r
364 }\r
365\r
366 if (*Value != ',') {\r
367 return EFI_INVALID_PARAMETER;\r
368 }\r
369\r
370 Value++;\r
371\r
372 //\r
373 // Check the master/slave setting, 1 for master, 0 for slave.\r
374 //\r
375 Num = NetStringToU32 (Value);\r
376\r
377 if ((Num != 0) && (Num != 1)) {\r
378 return EFI_INVALID_PARAMETER;\r
379 }\r
380\r
dab714aa 381 Option->Master = (BOOLEAN) (Num == 1);\r
772db4bb 382\r
383 while (NET_IS_DIGIT (*Value)) {\r
384 Value++;\r
385 }\r
386\r
387 if (*Value != '\0') {\r
388 return EFI_INVALID_PARAMETER;\r
389 }\r
390\r
391 return EFI_SUCCESS;\r
392}\r
393\r
394\r
395/**\r
396 Parse the option in Options array to MTFTP4_OPTION which program\r
397 can access directly.\r
398\r
399 @param Options The option array, which contains addresses of each\r
dab714aa 400 option's name/value string.\r
772db4bb 401 @param Count The number of options in the Options\r
402 @param Request Whether this is a request or OACK. The format of\r
403 multicast is different according to this setting.\r
6c047cfa 404 @param Operation The current performed operation.\r
772db4bb 405 @param MtftpOption The MTFTP4_OPTION for easy access.\r
406\r
407 @retval EFI_INVALID_PARAMETER The option is mal-formated\r
408 @retval EFI_UNSUPPORTED Some option isn't supported\r
409 @retval EFI_SUCCESS The option are OK and has been parsed.\r
410\r
411**/\r
412EFI_STATUS\r
413Mtftp4ParseOption (\r
dab714aa 414 IN EFI_MTFTP4_OPTION *Options,\r
415 IN UINT32 Count,\r
416 IN BOOLEAN Request,\r
6c047cfa 417 IN UINT16 Operation,\r
dab714aa 418 OUT MTFTP4_OPTION *MtftpOption\r
772db4bb 419 )\r
420{\r
421 EFI_STATUS Status;\r
422 UINT32 Index;\r
423 UINT32 Value;\r
424 EFI_MTFTP4_OPTION *This;\r
425\r
426 MtftpOption->Exist = 0;\r
427\r
428 for (Index = 0; Index < Count; Index++) {\r
429 This = Options + Index;\r
430\r
431 if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {\r
432 return EFI_INVALID_PARAMETER;\r
433 }\r
434\r
67a58d0f 435 if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "blksize")) {\r
772db4bb 436 //\r
437 // block size option, valid value is between [8, 65464]\r
438 //\r
439 Value = NetStringToU32 (This->ValueStr);\r
440\r
441 if ((Value < 8) || (Value > 65464)) {\r
442 return EFI_INVALID_PARAMETER;\r
443 }\r
444\r
445 MtftpOption->BlkSize = (UINT16) Value;\r
446 MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;\r
447\r
67a58d0f 448 } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "timeout")) {\r
772db4bb 449 //\r
450 // timeout option, valid value is between [1, 255]\r
451 //\r
452 Value = NetStringToU32 (This->ValueStr);\r
453\r
454 if ((Value < 1) || (Value > 255)) {\r
455 return EFI_INVALID_PARAMETER;\r
456 }\r
457\r
458 MtftpOption->Timeout = (UINT8) Value;\r
459\r
67a58d0f 460 } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "tsize")) {\r
772db4bb 461 //\r
462 // tsize option, the biggest transfer supported is 4GB with block size option\r
463 //\r
464 MtftpOption->Tsize = NetStringToU32 (This->ValueStr);\r
465 MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;\r
466\r
67a58d0f 467 } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "multicast")) {\r
772db4bb 468 //\r
469 // Multicast option, if it is a request, the value must be a zero\r
470 // length string, otherwise, it is formated like "204.0.0.1,1857,1\0"\r
471 //\r
472 if (Request) {\r
473 if (*(This->ValueStr) != '\0') {\r
474 return EFI_INVALID_PARAMETER;\r
475 }\r
476\r
477 } else {\r
478 Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);\r
479\r
480 if (EFI_ERROR (Status)) {\r
481 return Status;\r
482 }\r
483 }\r
484\r
485 MtftpOption->Exist |= MTFTP4_MCAST_EXIST;\r
486\r
6c047cfa
JW
487 } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "windowsize")) {\r
488 if (Operation == EFI_MTFTP4_OPCODE_WRQ) {\r
489 //\r
490 // Currently, windowsize is not supported in the write operation.\r
491 //\r
492 return EFI_UNSUPPORTED;\r
493 }\r
494\r
495 Value = NetStringToU32 (This->ValueStr);\r
496\r
497 if (Value < 1) {\r
498 return EFI_INVALID_PARAMETER;\r
499 }\r
500\r
501 MtftpOption->WindowSize = (UINT16) Value;\r
502 MtftpOption->Exist |= MTFTP4_WINDOWSIZE_EXIST;\r
772db4bb 503 } else if (Request) {\r
504 //\r
505 // Ignore the unsupported option if it is a reply, and return\r
506 // EFI_UNSUPPORTED if it's a request according to the UEFI spec.\r
507 //\r
508 return EFI_UNSUPPORTED;\r
509 }\r
510 }\r
511\r
512 return EFI_SUCCESS;\r
513}\r
514\r
515\r
516/**\r
517 Parse the options in the OACK packet to MTFTP4_OPTION which program\r
518 can access directly.\r
519\r
520 @param Packet The OACK packet to parse\r
521 @param PacketLen The length of the packet\r
6c047cfa 522 @param Operation The current performed operation.\r
772db4bb 523 @param MtftpOption The MTFTP_OPTION for easy access.\r
524\r
525 @retval EFI_INVALID_PARAMETER The packet option is mal-formated\r
526 @retval EFI_UNSUPPORTED Some option isn't supported\r
527 @retval EFI_SUCCESS The option are OK and has been parsed.\r
528\r
529**/\r
530EFI_STATUS\r
531Mtftp4ParseOptionOack (\r
dab714aa 532 IN EFI_MTFTP4_PACKET *Packet,\r
533 IN UINT32 PacketLen,\r
6c047cfa 534 IN UINT16 Operation,\r
dab714aa 535 OUT MTFTP4_OPTION *MtftpOption\r
772db4bb 536 )\r
537{\r
538 EFI_MTFTP4_OPTION *OptionList;\r
539 EFI_STATUS Status;\r
540 UINT32 Count;\r
541\r
542 MtftpOption->Exist = 0;\r
543\r
544 Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);\r
545\r
546 if (EFI_ERROR (Status) || (Count == 0)) {\r
547 return Status;\r
548 }\r
e2851998 549 ASSERT (OptionList != NULL);\r
772db4bb 550\r
6c047cfa 551 Status = Mtftp4ParseOption (OptionList, Count, FALSE, Operation, MtftpOption);\r
772db4bb 552\r
766c7483 553 FreePool (OptionList);\r
772db4bb 554 return Status;\r
555}\r