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