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