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