Home | History | Annotate | Download | only in Mtftp6Dxe
      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
     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
    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
    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
    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