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