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