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