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