1 /** @file
2   Mtftp6 option parse functions implementation.
3 
4   Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
5 
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php.
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "Mtftp6Impl.h"
17 
18 CHAR8 *mMtftp6SupportedOptions[MTFTP6_SUPPORTED_OPTIONS_NUM] = {
19   "blksize",
20   "timeout",
21   "tsize",
22   "multicast"
23 };
24 
25 
26 /**
27   Parse the NULL terminated ASCII string of multicast option.
28 
29   @param[in]  Str           The pointer to the Ascii string of multicast option.
30   @param[in]  ExtInfo       The pointer to the option information to be filled.
31 
32   @retval EFI_SUCCESS            Parse the multicast option successfully.
33   @retval EFI_INVALID_PARAMETER  The string is malformatted.
34   @retval EFI_OUT_OF_RESOURCES   Failed to perform the operation due to lack of
35                                  resources.
36 
37 **/
38 EFI_STATUS
Mtftp6ParseMcastOption(IN UINT8 * Str,IN MTFTP6_EXT_OPTION_INFO * ExtInfo)39 Mtftp6ParseMcastOption (
40   IN UINT8                  *Str,
41   IN MTFTP6_EXT_OPTION_INFO *ExtInfo
42   )
43 {
44   EFI_STATUS                Status;
45   UINT32                    Num;
46   CHAR8                     *Ip6Str;
47   CHAR8                     *TempStr;
48 
49   //
50   // The multicast option is formated like "addr,port,mc"
51   // The server can also omit the ip and port, use ",,1"
52   //
53   if (*Str == ',') {
54 
55     ZeroMem (&ExtInfo->McastIp, sizeof (EFI_IPv6_ADDRESS));
56   } else {
57 
58     Ip6Str = (CHAR8 *) AllocateCopyPool (AsciiStrSize ((CHAR8 *) Str), Str);
59     if (Ip6Str == NULL) {
60       return EFI_OUT_OF_RESOURCES;
61     }
62 
63     //
64     // The IPv6 address locates before comma in the input Str.
65     //
66     TempStr = Ip6Str;
67     while ((*TempStr != '\0') && (*TempStr != ',')) {
68       TempStr++;
69     }
70 
71     *TempStr = '\0';
72 
73     Status = NetLibAsciiStrToIp6 (Ip6Str, &ExtInfo->McastIp);
74     FreePool (Ip6Str);
75 
76     if (EFI_ERROR (Status)) {
77       return Status;
78     }
79 
80     while ((*Str != '\0') && (*Str != ',')) {
81       Str++;
82     }
83   }
84 
85   if (*Str != ',') {
86     return EFI_INVALID_PARAMETER;
87   }
88 
89   Str++;
90 
91   //
92   // Convert the port setting. the server can send us a port number or
93   // empty string. such as the port in ",,1"
94   //
95   if (*Str == ',') {
96 
97     ExtInfo->McastPort = 0;
98   } else {
99 
100     Num = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Str);
101 
102     if (Num > 65535) {
103       return EFI_INVALID_PARAMETER;
104     }
105 
106     ExtInfo->McastPort = (UINT16) Num;
107 
108     while (NET_IS_DIGIT (*Str)) {
109       Str++;
110     }
111   }
112 
113   if (*Str != ',') {
114     return EFI_INVALID_PARAMETER;
115   }
116 
117   Str++;
118 
119   //
120   // Check the master/slave setting, 1 for master, 0 for slave.
121   //
122   Num = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Str);
123 
124   if (Num != 0 && Num != 1) {
125     return EFI_INVALID_PARAMETER;
126   }
127 
128   ExtInfo->IsMaster = (BOOLEAN) (Num == 1);
129 
130   while (NET_IS_DIGIT (*Str)) {
131     Str++;
132   }
133 
134   if (*Str != '\0') {
135     return EFI_INVALID_PARAMETER;
136   }
137 
138   return EFI_SUCCESS;
139 }
140 
141 
142 /**
143   Parse the MTFTP6 extesion options.
144 
145   @param[in]  Options       The pointer to the extension options list.
146   @param[in]  Count         The num of the extension options.
147   @param[in]  IsRequest     If FALSE, the extension options is included
148                             by a request packet.
149   @param[in]  ExtInfo       The pointer to the option information to be filled.
150 
151   @retval EFI_SUCCESS            Parse the multicast option successfully.
152   @retval EFI_INVALID_PARAMETER  There is one option is malformatted at least.
153   @retval EFI_UNSUPPORTED        There is one option is not supported at least.
154 
155 **/
156 EFI_STATUS
Mtftp6ParseExtensionOption(IN EFI_MTFTP6_OPTION * Options,IN UINT32 Count,IN BOOLEAN IsRequest,IN MTFTP6_EXT_OPTION_INFO * ExtInfo)157 Mtftp6ParseExtensionOption (
158   IN EFI_MTFTP6_OPTION        *Options,
159   IN UINT32                   Count,
160   IN BOOLEAN                  IsRequest,
161   IN MTFTP6_EXT_OPTION_INFO   *ExtInfo
162   )
163 {
164   EFI_STATUS                  Status;
165   EFI_MTFTP6_OPTION           *Opt;
166   UINT32                      Index;
167   UINT32                      Value;
168 
169   ExtInfo->BitMap = 0;
170 
171   for (Index = 0; Index < Count; Index++) {
172 
173     Opt = Options + Index;
174 
175     if (Opt->OptionStr == NULL || Opt->ValueStr == NULL) {
176       return EFI_INVALID_PARAMETER;
177     }
178 
179     if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "blksize") == 0) {
180       //
181       // block size option, valid value is between [8, 65464]
182       //
183       Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
184 
185       if ((Value < 8) || (Value > 65464)) {
186         return EFI_INVALID_PARAMETER;
187       }
188 
189       ExtInfo->BlkSize = (UINT16) Value;
190       ExtInfo->BitMap |= MTFTP6_OPT_BLKSIZE_BIT;
191 
192     } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "timeout") == 0) {
193       //
194       // timeout option, valid value is between [1, 255]
195       //
196       Value = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
197 
198       if (Value < 1 || Value > 255) {
199         return EFI_INVALID_PARAMETER;
200       }
201 
202       ExtInfo->Timeout = (UINT8) Value;
203       ExtInfo->BitMap |= MTFTP6_OPT_TIMEOUT_BIT;
204 
205     } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "tsize") == 0) {
206       //
207       // tsize option, the biggest transfer supported is 4GB with block size option
208       //
209       ExtInfo->Tsize   = (UINT32) AsciiStrDecimalToUintn ((CHAR8 *) Opt->ValueStr);
210       ExtInfo->BitMap |= MTFTP6_OPT_TSIZE_BIT;
211 
212     } else if (AsciiStriCmp ((CHAR8 *) Opt->OptionStr, "multicast") == 0) {
213       //
214       // Multicast option, if it is a request, the value must be a zero string,
215       // otherwise, it must be like "addr,port,mc" string, mc indicates master.
216       //
217       if (!IsRequest) {
218 
219         Status = Mtftp6ParseMcastOption (Opt->ValueStr, ExtInfo);
220 
221         if (EFI_ERROR (Status)) {
222           return Status;
223         }
224       } else if (*(Opt->ValueStr) != '\0') {
225 
226         return EFI_INVALID_PARAMETER;
227       }
228 
229       ExtInfo->BitMap |= MTFTP6_OPT_MCAST_BIT;
230 
231     } else if (IsRequest) {
232       //
233       // If it's a request, unsupported; else if it's a reply, ignore.
234       //
235       return EFI_UNSUPPORTED;
236     }
237   }
238 
239   return EFI_SUCCESS;
240 }
241 
242 
243 /**
244   Go through the packet to fill the options array with the start
245   addresses of each MTFTP option name/value pair.
246 
247   @param[in]      Packet                 The packet to be checked.
248   @param[in]      PacketLen              The length of the packet.
249   @param[in, out] Count                  The num of the Options on input.
250                                          The actual one on output.
251   @param[in]      Options                The option array to be filled.
252                                          It is optional.
253 
254   @retval EFI_SUCCESS            The packet has been parsed successfully.
255   @retval EFI_INVALID_PARAMETER  The packet is malformatted.
256   @retval EFI_BUFFER_TOO_SMALL   The Options array is too small.
257   @retval EFI_PROTOCOL_ERROR     An unexpected MTFTPv6 packet was received.
258 
259 **/
260 EFI_STATUS
Mtftp6ParsePacketOption(IN EFI_MTFTP6_PACKET * Packet,IN UINT32 PacketLen,IN OUT UINT32 * Count,IN EFI_MTFTP6_OPTION * Options OPTIONAL)261 Mtftp6ParsePacketOption (
262   IN     EFI_MTFTP6_PACKET     *Packet,
263   IN     UINT32                PacketLen,
264   IN OUT UINT32                *Count,
265   IN     EFI_MTFTP6_OPTION     *Options          OPTIONAL
266   )
267 {
268   UINT8                        *Cur;
269   UINT8                        *Last;
270   UINT8                        Num;
271   UINT8                        *Name;
272   UINT8                        *Value;
273 
274   Num   = 0;
275   Cur   = (UINT8 *) Packet + MTFTP6_OPCODE_LEN;
276   Last  = (UINT8 *) Packet + PacketLen - 1;
277 
278   //
279   // process option name and value pairs.
280   // The last byte is always zero.
281   //
282   while (Cur < Last) {
283     Name = Cur;
284 
285     while (*Cur != 0) {
286       Cur++;
287     }
288 
289     if (Cur == Last) {
290       return EFI_PROTOCOL_ERROR;
291     }
292 
293     Value = ++Cur;
294 
295     while (*Cur != 0) {
296       Cur++;
297     }
298 
299     Num++;
300 
301     if (Options != NULL && Num <= *Count) {
302       Options[Num - 1].OptionStr  = Name;
303       Options[Num - 1].ValueStr   = Value;
304     }
305 
306     Cur++;
307   }
308 
309   //
310   // Return buffer too small if the buffer passed-in isn't enough.
311   //
312   if (*Count < Num || Options == NULL) {
313     *Count = Num;
314     return EFI_BUFFER_TOO_SMALL;
315   }
316 
317   *Count = Num;
318   return EFI_SUCCESS;
319 }
320 
321 
322 /**
323   Go through the packet, generate option list array and fill it
324   by the result of parse options.
325 
326   @param[in]      Packet                 The packet to be checked.
327   @param[in]      PacketLen              The length of the packet.
328   @param[in, out] OptionCount            The num of the Options on input.
329                                          The actual one on output.
330   @param[out]     OptionList             The option list array to be generated
331                                          and filled. It is optional.
332 
333   @retval EFI_SUCCESS            The packet has been parsed successfully.
334   @retval EFI_INVALID_PARAMETER  The packet is malformatted.
335   @retval EFI_PROTOCOL_ERROR     There is one option is malformatted at least.
336   @retval EFI_NOT_FOUND          The packet has no options.
337   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for the array.
338   @retval EFI_BUFFER_TOO_SMALL   The size of option list array is too small.
339 
340 **/
341 EFI_STATUS
Mtftp6ParseStart(IN EFI_MTFTP6_PACKET * Packet,IN UINT32 PacketLen,IN OUT UINT32 * OptionCount,OUT EFI_MTFTP6_OPTION ** OptionList OPTIONAL)342 Mtftp6ParseStart (
343   IN     EFI_MTFTP6_PACKET      *Packet,
344   IN     UINT32                 PacketLen,
345   IN OUT UINT32                 *OptionCount,
346      OUT EFI_MTFTP6_OPTION      **OptionList          OPTIONAL
347   )
348 {
349   EFI_STATUS                    Status;
350 
351   if (PacketLen == 0 || Packet == NULL || OptionCount == NULL) {
352     return EFI_INVALID_PARAMETER;
353   }
354 
355   *OptionCount = 0;
356 
357   if (OptionList != NULL) {
358     *OptionList = NULL;
359   }
360 
361   if (NTOHS (Packet->OpCode) != EFI_MTFTP6_OPCODE_OACK) {
362     return EFI_INVALID_PARAMETER;
363   }
364 
365   //
366   // The last byte must be zero to terminate the options.
367   //
368   if (*((UINT8 *) Packet + PacketLen - 1) != 0) {
369     return EFI_PROTOCOL_ERROR;
370   }
371 
372   //
373   // Parse packet with NULL buffer for the first time to get the number
374   // of options in the packet.
375   //
376   Status = Mtftp6ParsePacketOption (Packet, PacketLen, OptionCount, NULL);
377 
378   if (Status != EFI_BUFFER_TOO_SMALL) {
379     return Status;
380   }
381 
382   //
383   // Return not found if there is no option parsed.
384   //
385   if (*OptionCount == 0) {
386     return EFI_NOT_FOUND;
387   }
388 
389   //
390   // Only need parse out the number of options.
391   //
392   if (OptionList == NULL) {
393     return EFI_SUCCESS;
394   }
395 
396   //
397   // Allocate the buffer according to the option number parsed before.
398   //
399   *OptionList = AllocateZeroPool (*OptionCount * sizeof (EFI_MTFTP6_OPTION));
400 
401   if (*OptionList == NULL) {
402     return EFI_OUT_OF_RESOURCES;
403   }
404 
405   //
406   // Parse packet with allocated buffer for the second time to fill the pointer array
407   // of the options in the packet.
408   //
409   Status = Mtftp6ParsePacketOption (Packet, PacketLen, OptionCount, *OptionList);
410 
411   if (EFI_ERROR (Status)) {
412     return Status;
413   }
414 
415   return EFI_SUCCESS;
416 }
417