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
18CHAR8 *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**/
38EFI_STATUS
39Mtftp6ParseMcastOption (
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**/
156EFI_STATUS
157Mtftp6ParseExtensionOption (
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**/
260EFI_STATUS
261Mtftp6ParsePacketOption (
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**/
341EFI_STATUS
342Mtftp6ParseStart (
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