Home | History | Annotate | Download | only in Ip4Dxe
      1 /** @file
      2   IP4 option support functions.
      3 
      4 Copyright (c) 2005 - 2011, 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
      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 "Ip4Impl.h"
     16 
     17 
     18 /**
     19   Validate the IP4 option format for both the packets we received
     20   and will transmit.
     21 
     22   @param[in]  Option            The first byte of the option
     23   @param[in]  OptionLen         The length of the whole option
     24   @param[in]  Rcvd              The option is from the packet we received if TRUE,
     25                                 otherwise the option we wants to transmit.
     26 
     27   @retval TRUE     The option is properly formatted
     28   @retval FALSE    The option is mal-formated
     29 
     30 **/
     31 BOOLEAN
     32 Ip4OptionIsValid (
     33   IN UINT8                  *Option,
     34   IN UINT32                 OptionLen,
     35   IN BOOLEAN                Rcvd
     36   )
     37 {
     38   UINT32                    Cur;
     39   UINT32                    Len;
     40   UINT32                    Point;
     41 
     42   Cur       = 0;
     43 
     44   while (Cur < OptionLen) {
     45     switch (Option[Cur]) {
     46     case IP4_OPTION_NOP:
     47       Cur++;
     48       break;
     49 
     50     case IP4_OPTION_EOP:
     51       Cur = OptionLen;
     52       break;
     53 
     54     case IP4_OPTION_LSRR:
     55     case IP4_OPTION_SSRR:
     56     case IP4_OPTION_RR:
     57       Len   = Option[Cur + 1];
     58       Point = Option[Cur + 2];
     59 
     60       //
     61       // SRR/RR options are formatted as |Type|Len|Point|Ip1|Ip2|...
     62       //
     63       if ((OptionLen - Cur < Len) || (Len < 3) || ((Len - 3) % 4 != 0)) {
     64         return FALSE;
     65       }
     66 
     67       if ((Point > Len + 1) || (Point % 4 != 0)) {
     68         return FALSE;
     69       }
     70 
     71       //
     72       // The Point must point pass the last entry if the packet is received
     73       // by us. It must point to 4 if the packet is to be sent by us for
     74       // source route option.
     75       //
     76       if ((Option[Cur] != IP4_OPTION_RR) &&
     77           ((Rcvd && (Point != Len + 1)) || (!Rcvd && (Point != 4)))) {
     78 
     79         return FALSE;
     80       }
     81 
     82       Cur += Len;
     83       break;
     84 
     85     default:
     86       Len = Option[Cur + 1];
     87 
     88       if ((OptionLen - Cur < Len) || (Len < 2)) {
     89         return FALSE;
     90       }
     91 
     92       Cur = Cur + Len;
     93       break;
     94     }
     95 
     96   }
     97 
     98   return TRUE;
     99 }
    100 
    101 
    102 /**
    103   Copy the option from the original option to buffer. It
    104   handles the details such as:
    105   1. whether copy the single IP4 option to the first/non-first
    106      fragments.
    107   2. Pad the options copied over to aligned to 4 bytes.
    108 
    109   @param[in]       Option            The original option to copy from
    110   @param[in]       OptionLen         The length of the original option
    111   @param[in]       FirstFragment     Whether it is the first fragment
    112   @param[in, out]  Buf               The buffer to copy options to. NULL
    113   @param[in, out]  BufLen            The length of the buffer
    114 
    115   @retval EFI_SUCCESS           The options are copied over
    116   @retval EFI_BUFFER_TOO_SMALL  Buf is NULL or BufLen provided is too small.
    117 
    118 **/
    119 EFI_STATUS
    120 Ip4CopyOption (
    121   IN     UINT8              *Option,
    122   IN     UINT32             OptionLen,
    123   IN     BOOLEAN            FirstFragment,
    124   IN OUT UINT8              *Buf,           OPTIONAL
    125   IN OUT UINT32             *BufLen
    126   )
    127 {
    128   UINT8                     OptBuf[40];
    129   UINT32                    Cur;
    130   UINT32                    Next;
    131   UINT8                     Type;
    132   UINT32                    Len;
    133 
    134   ASSERT ((BufLen != NULL) && (OptionLen <= 40));
    135 
    136   Cur   = 0;
    137   Next  = 0;
    138 
    139   while (Cur < OptionLen) {
    140     Type  = Option[Cur];
    141     Len   = Option[Cur + 1];
    142 
    143     if (Type == IP4_OPTION_NOP) {
    144       //
    145       // Keep the padding, in case that the sender wants to align
    146       // the option, say, to 4 bytes
    147       //
    148       OptBuf[Next] = IP4_OPTION_NOP;
    149       Next++;
    150       Cur++;
    151 
    152     } else if (Type == IP4_OPTION_EOP) {
    153       //
    154       // Don't append the EOP to avoid including only a EOP option
    155       //
    156       break;
    157 
    158     } else {
    159       //
    160       // don't copy options that is only valid for the first fragment
    161       //
    162       if (FirstFragment || (Type & IP4_OPTION_COPY_MASK) != 0) {
    163         CopyMem (OptBuf + Next, Option + Cur, Len);
    164         Next += Len;
    165       }
    166 
    167       Cur += Len;
    168     }
    169   }
    170 
    171   //
    172   // Don't append an EOP only option.
    173   //
    174   if (Next == 0) {
    175     *BufLen = 0;
    176     return EFI_SUCCESS;
    177   }
    178 
    179   //
    180   // Append an EOP if the end of option doesn't coincide with the
    181   // end of the IP header, that is, isn't aligned to 4 bytes..
    182   //
    183   if ((Next % 4) != 0) {
    184     OptBuf[Next] = IP4_OPTION_EOP;
    185     Next++;
    186   }
    187 
    188   //
    189   // Head length is in the unit of 4 bytes. Now, Len is the
    190   // acutal option length to appear in the IP header.
    191   //
    192   Len = ((Next + 3) &~0x03);
    193 
    194   //
    195   // If the buffer is too small, set the BufLen then return
    196   //
    197   if ((Buf == NULL) || (*BufLen < Len)) {
    198     *BufLen = Len;
    199     return EFI_BUFFER_TOO_SMALL;
    200   }
    201 
    202   //
    203   // Copy the option to the Buf, zero the buffer first to pad
    204   // the options with NOP to align to 4 bytes.
    205   //
    206   ZeroMem (Buf, Len);
    207   CopyMem (Buf, OptBuf, Next);
    208   *BufLen = Len;
    209   return EFI_SUCCESS;
    210 }
    211