Home | History | Annotate | Download | only in Mtftp4Dxe
      1 /** @file
      2   Routines to process MTFTP4 options.
      3 
      4 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php<BR>
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Mtftp4Impl.h"
     16 
     17 CHAR8 *mMtftp4SupportedOptions[MTFTP4_SUPPORTED_OPTIONS] = {
     18   "blksize",
     19   "timeout",
     20   "tsize",
     21   "multicast"
     22 };
     23 
     24 
     25 /**
     26   Check whether two ascii strings are equel, ignore the case.
     27 
     28   @param  Str1                   The first ascii string
     29   @param  Str2                   The second ascii string
     30 
     31   @retval TRUE                   Two strings are equal when case is ignored.
     32   @retval FALSE                  Two string are not equal.
     33 
     34 **/
     35 BOOLEAN
     36 NetStringEqualNoCase (
     37   IN UINT8                 *Str1,
     38   IN UINT8                 *Str2
     39   )
     40 {
     41   UINT8                     Ch1;
     42   UINT8                     Ch2;
     43 
     44   ASSERT ((Str1 != NULL) && (Str2 != NULL));
     45 
     46   for (; (*Str1 != '\0') && (*Str2 != '\0'); Str1++, Str2++) {
     47     Ch1 = *Str1;
     48     Ch2 = *Str2;
     49 
     50     //
     51     // Convert them to lower case then compare two
     52     //
     53     if (('A' <= Ch1) && (Ch1 <= 'Z')) {
     54       Ch1 += 'a' - 'A';
     55     }
     56 
     57     if (('A' <= Ch2) && (Ch2 <= 'Z')) {
     58       Ch2 += 'a' - 'A';
     59     }
     60 
     61     if (Ch1 != Ch2) {
     62       return FALSE;
     63     }
     64   }
     65 
     66   return (BOOLEAN) (*Str1 == *Str2);
     67 }
     68 
     69 
     70 /**
     71   Convert a string to a UINT32 number.
     72 
     73   @param  Str                    The string to convert from
     74 
     75   @return The number get from the string
     76 
     77 **/
     78 UINT32
     79 NetStringToU32 (
     80   IN UINT8                 *Str
     81   )
     82 {
     83   UINT32                    Num;
     84 
     85   ASSERT (Str != NULL);
     86 
     87   Num = 0;
     88 
     89   for (; NET_IS_DIGIT (*Str); Str++) {
     90     Num = Num * 10 + (*Str - '0');
     91   }
     92 
     93   return Num;
     94 }
     95 
     96 
     97 /**
     98   Convert a string of the format "192.168.0.1" to an IP address.
     99 
    100   @param  Str                    The string representation of IP
    101   @param  Ip                     The varible to get IP.
    102 
    103   @retval EFI_INVALID_PARAMETER  The IP string is invalid.
    104   @retval EFI_SUCCESS            The IP is parsed into the Ip
    105 
    106 **/
    107 EFI_STATUS
    108 NetStringToIp (
    109   IN     UINT8                 *Str,
    110      OUT IP4_ADDR              *Ip
    111   )
    112 {
    113   UINT32                    Byte;
    114   UINT32                    Addr;
    115   UINTN                     Index;
    116 
    117   *Ip  = 0;
    118   Addr = 0;
    119 
    120   for (Index = 0; Index < 4; Index++) {
    121     if (!NET_IS_DIGIT (*Str)) {
    122       return EFI_INVALID_PARAMETER;
    123     }
    124 
    125     Byte = NetStringToU32 (Str);
    126 
    127     if (Byte > 255) {
    128       return EFI_INVALID_PARAMETER;
    129     }
    130 
    131     Addr = (Addr << 8) | Byte;
    132 
    133     //
    134     // Skip all the digitals and check whether the sepeator is the dot
    135     //
    136     while (NET_IS_DIGIT (*Str)) {
    137       Str++;
    138     }
    139 
    140     if ((Index < 3) && (*Str != '.')) {
    141       return EFI_INVALID_PARAMETER;
    142     }
    143 
    144     Str++;
    145   }
    146 
    147   *Ip = Addr;
    148 
    149   return EFI_SUCCESS;
    150 }
    151 
    152 
    153 /**
    154   Go through the packet to fill the Options array with the start
    155   addresses of each MTFTP option name/value pair.
    156 
    157   @param  Packet                 The packet to check
    158   @param  PacketLen              The packet's length
    159   @param  Count                  The size of the Options on input. The actual
    160                                  options on output
    161   @param  Options                The option array to fill in
    162 
    163   @retval EFI_INVALID_PARAMETER  The packet is mal-formated
    164   @retval EFI_BUFFER_TOO_SMALL   The Options array is too small
    165   @retval EFI_SUCCESS            The packet has been parsed into the Options array.
    166 
    167 **/
    168 EFI_STATUS
    169 Mtftp4FillOptions (
    170   IN     EFI_MTFTP4_PACKET     *Packet,
    171   IN     UINT32                PacketLen,
    172   IN OUT UINT32                *Count,
    173      OUT EFI_MTFTP4_OPTION     *Options          OPTIONAL
    174   )
    175 {
    176   UINT8                     *Cur;
    177   UINT8                     *Last;
    178   UINT8                     Num;
    179   UINT8                     *Name;
    180   UINT8                     *Value;
    181 
    182   Num   = 0;
    183   Cur   = (UINT8 *) Packet + MTFTP4_OPCODE_LEN;
    184   Last  = (UINT8 *) Packet + PacketLen - 1;
    185 
    186   //
    187   // process option name and value pairs. The last byte is always zero
    188   //
    189   while (Cur < Last) {
    190     Name = Cur;
    191 
    192     while (*Cur != 0) {
    193       Cur++;
    194     }
    195 
    196     if (Cur == Last) {
    197       return EFI_INVALID_PARAMETER;
    198     }
    199 
    200     Value = ++Cur;
    201 
    202     while (*Cur != 0) {
    203       Cur++;
    204     }
    205 
    206     Num++;
    207 
    208     if ((Options != NULL) && (Num <= *Count)) {
    209       Options[Num - 1].OptionStr  = Name;
    210       Options[Num - 1].ValueStr   = Value;
    211     }
    212 
    213     Cur++;
    214   }
    215 
    216   if ((*Count < Num) || (Options == NULL)) {
    217     *Count = Num;
    218     return EFI_BUFFER_TOO_SMALL;
    219   }
    220 
    221   *Count = Num;
    222   return EFI_SUCCESS;
    223 }
    224 
    225 
    226 /**
    227   Allocate and fill in a array of Mtftp options from the Packet.
    228 
    229   It first calls Mtftp4FillOption to get the option number, then allocate
    230   the array, at last, call Mtftp4FillOption again to save the options.
    231 
    232   @param  Packet                 The packet to parse
    233   @param  PacketLen              The length of the packet
    234   @param  OptionCount            The number of options in the packet
    235   @param  OptionList             The point to get the option array.
    236 
    237   @retval EFI_INVALID_PARAMETER  The parametera are invalid or packet isn't a
    238                                  well-formated OACK packet.
    239   @retval EFI_SUCCESS            The option array is build
    240   @retval EFI_OUT_OF_RESOURCES   Failed to allocate memory for the array
    241 
    242 **/
    243 EFI_STATUS
    244 Mtftp4ExtractOptions (
    245   IN     EFI_MTFTP4_PACKET     *Packet,
    246   IN     UINT32                PacketLen,
    247      OUT UINT32                *OptionCount,
    248      OUT EFI_MTFTP4_OPTION     **OptionList        OPTIONAL
    249   )
    250 {
    251   EFI_STATUS                Status;
    252 
    253   *OptionCount = 0;
    254 
    255   if (OptionList != NULL) {
    256     *OptionList = NULL;
    257   }
    258 
    259   if (NTOHS (Packet->OpCode) != EFI_MTFTP4_OPCODE_OACK) {
    260     return EFI_INVALID_PARAMETER;
    261   }
    262 
    263   if (PacketLen == MTFTP4_OPCODE_LEN) {
    264     return EFI_SUCCESS;
    265   }
    266 
    267   //
    268   // The last byte must be zero to terminate the options
    269   //
    270   if (*((UINT8 *) Packet + PacketLen - 1) != 0) {
    271     return EFI_INVALID_PARAMETER;
    272   }
    273 
    274   //
    275   // Get the number of options
    276   //
    277   Status = Mtftp4FillOptions (Packet, PacketLen, OptionCount, NULL);
    278 
    279   if ((Status == EFI_SUCCESS) || (Status != EFI_BUFFER_TOO_SMALL)) {
    280     return Status;
    281   }
    282 
    283   //
    284   // Allocate memory for the options, then call Mtftp4FillOptions to
    285   // fill it if caller want that.
    286   //
    287   if (OptionList == NULL) {
    288     return EFI_SUCCESS;
    289   }
    290 
    291   *OptionList = AllocatePool (*OptionCount * sizeof (EFI_MTFTP4_OPTION));
    292 
    293   if (*OptionList == NULL) {
    294     return EFI_OUT_OF_RESOURCES;
    295   }
    296 
    297   Mtftp4FillOptions (Packet, PacketLen, OptionCount, *OptionList);
    298   return EFI_SUCCESS;
    299 }
    300 
    301 
    302 /**
    303   Parse the MTFTP multicast option.
    304 
    305   @param  Value                  The Mtftp multicast value string
    306   @param  Option                 The option to save the info into.
    307 
    308   @retval EFI_INVALID_PARAMETER  The multicast value string is invalid.
    309   @retval EFI_SUCCESS            The multicast value is parsed into the Option
    310 
    311 **/
    312 EFI_STATUS
    313 Mtftp4ExtractMcast (
    314   IN     UINT8                  *Value,
    315   IN OUT MTFTP4_OPTION          *Option
    316   )
    317 {
    318   EFI_STATUS                Status;
    319   UINT32                    Num;
    320 
    321   //
    322   // The multicast option is formated like "204.0.0.1,1857,1"
    323   // The server can also omit the ip and port, use ",,1"
    324   //
    325   if (*Value == ',') {
    326     Option->McastIp   = 0;
    327   } else {
    328     Status = NetStringToIp (Value, &Option->McastIp);
    329 
    330     if (EFI_ERROR (Status)) {
    331       return Status;
    332     }
    333 
    334     while ((*Value != 0) && (*Value != ',')) {
    335       Value++;
    336     }
    337   }
    338 
    339   if (*Value != ',') {
    340     return EFI_INVALID_PARAMETER;
    341   }
    342 
    343   Value++;
    344 
    345   //
    346   // Convert the port setting. the server can send us a port number or
    347   // empty string. such as the port in ",,1"
    348   //
    349   if (*Value == ',') {
    350     Option->McastPort = 0;
    351   } else {
    352     Num = NetStringToU32 (Value);
    353 
    354     if (Num > 65535) {
    355       return EFI_INVALID_PARAMETER;
    356     }
    357 
    358     Option->McastPort = (UINT16) Num;
    359 
    360     while (NET_IS_DIGIT (*Value)) {
    361       Value++;
    362     }
    363   }
    364 
    365   if (*Value != ',') {
    366     return EFI_INVALID_PARAMETER;
    367   }
    368 
    369   Value++;
    370 
    371   //
    372   // Check the master/slave setting, 1 for master, 0 for slave.
    373   //
    374   Num = NetStringToU32 (Value);
    375 
    376   if ((Num != 0) && (Num != 1)) {
    377     return EFI_INVALID_PARAMETER;
    378   }
    379 
    380   Option->Master = (BOOLEAN) (Num == 1);
    381 
    382   while (NET_IS_DIGIT (*Value)) {
    383     Value++;
    384   }
    385 
    386   if (*Value != '\0') {
    387     return EFI_INVALID_PARAMETER;
    388   }
    389 
    390   return EFI_SUCCESS;
    391 }
    392 
    393 
    394 /**
    395   Parse the option in Options array to MTFTP4_OPTION which program
    396   can access directly.
    397 
    398   @param  Options                The option array, which contains addresses of each
    399                                  option's name/value string.
    400   @param  Count                  The number of options in the Options
    401   @param  Request                Whether this is a request or OACK. The format of
    402                                  multicast is different according to this setting.
    403   @param  MtftpOption            The MTFTP4_OPTION for easy access.
    404 
    405   @retval EFI_INVALID_PARAMETER  The option is mal-formated
    406   @retval EFI_UNSUPPORTED        Some option isn't supported
    407   @retval EFI_SUCCESS            The option are OK and has been parsed.
    408 
    409 **/
    410 EFI_STATUS
    411 Mtftp4ParseOption (
    412   IN     EFI_MTFTP4_OPTION     *Options,
    413   IN     UINT32                Count,
    414   IN     BOOLEAN               Request,
    415      OUT MTFTP4_OPTION         *MtftpOption
    416   )
    417 {
    418   EFI_STATUS                Status;
    419   UINT32                    Index;
    420   UINT32                    Value;
    421   EFI_MTFTP4_OPTION         *This;
    422 
    423   MtftpOption->Exist = 0;
    424 
    425   for (Index = 0; Index < Count; Index++) {
    426     This = Options + Index;
    427 
    428     if ((This->OptionStr == NULL) || (This->ValueStr == NULL)) {
    429       return EFI_INVALID_PARAMETER;
    430     }
    431 
    432     if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "blksize")) {
    433       //
    434       // block size option, valid value is between [8, 65464]
    435       //
    436       Value = NetStringToU32 (This->ValueStr);
    437 
    438       if ((Value < 8) || (Value > 65464)) {
    439         return EFI_INVALID_PARAMETER;
    440       }
    441 
    442       MtftpOption->BlkSize = (UINT16) Value;
    443       MtftpOption->Exist |= MTFTP4_BLKSIZE_EXIST;
    444 
    445     } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "timeout")) {
    446       //
    447       // timeout option, valid value is between [1, 255]
    448       //
    449       Value = NetStringToU32 (This->ValueStr);
    450 
    451       if ((Value < 1) || (Value > 255)) {
    452         return EFI_INVALID_PARAMETER;
    453       }
    454 
    455       MtftpOption->Timeout = (UINT8) Value;
    456 
    457     } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "tsize")) {
    458       //
    459       // tsize option, the biggest transfer supported is 4GB with block size option
    460       //
    461       MtftpOption->Tsize = NetStringToU32 (This->ValueStr);
    462       MtftpOption->Exist |= MTFTP4_TSIZE_EXIST;
    463 
    464     } else if (NetStringEqualNoCase (This->OptionStr, (UINT8 *) "multicast")) {
    465       //
    466       // Multicast option, if it is a request, the value must be a zero
    467       // length string, otherwise, it is formated like "204.0.0.1,1857,1\0"
    468       //
    469       if (Request) {
    470         if (*(This->ValueStr) != '\0') {
    471           return EFI_INVALID_PARAMETER;
    472         }
    473 
    474       } else {
    475         Status = Mtftp4ExtractMcast (This->ValueStr, MtftpOption);
    476 
    477         if (EFI_ERROR (Status)) {
    478           return Status;
    479         }
    480       }
    481 
    482       MtftpOption->Exist |= MTFTP4_MCAST_EXIST;
    483 
    484     } else if (Request) {
    485       //
    486       // Ignore the unsupported option if it is a reply, and return
    487       // EFI_UNSUPPORTED if it's a request according to the UEFI spec.
    488       //
    489       return EFI_UNSUPPORTED;
    490     }
    491   }
    492 
    493   return EFI_SUCCESS;
    494 }
    495 
    496 
    497 /**
    498   Parse the options in the OACK packet to MTFTP4_OPTION which program
    499   can access directly.
    500 
    501   @param  Packet                 The OACK packet to parse
    502   @param  PacketLen              The length of the packet
    503   @param  MtftpOption            The MTFTP_OPTION for easy access.
    504 
    505   @retval EFI_INVALID_PARAMETER  The packet option is mal-formated
    506   @retval EFI_UNSUPPORTED        Some option isn't supported
    507   @retval EFI_SUCCESS            The option are OK and has been parsed.
    508 
    509 **/
    510 EFI_STATUS
    511 Mtftp4ParseOptionOack (
    512   IN     EFI_MTFTP4_PACKET     *Packet,
    513   IN     UINT32                PacketLen,
    514      OUT MTFTP4_OPTION         *MtftpOption
    515   )
    516 {
    517   EFI_MTFTP4_OPTION *OptionList;
    518   EFI_STATUS        Status;
    519   UINT32            Count;
    520 
    521   MtftpOption->Exist = 0;
    522 
    523   Status = Mtftp4ExtractOptions (Packet, PacketLen, &Count, &OptionList);
    524 
    525   if (EFI_ERROR (Status) || (Count == 0)) {
    526     return Status;
    527   }
    528   ASSERT (OptionList != NULL);
    529 
    530   Status = Mtftp4ParseOption (OptionList, Count, FALSE, MtftpOption);
    531 
    532   FreePool (OptionList);
    533   return Status;
    534 }
    535