Home | History | Annotate | Download | only in TcpDxe
      1 /** @file
      2   Routines to process TCP option.
      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 "TcpMain.h"
     17 
     18 /**
     19   Get a UINT16 value from buffer.
     20 
     21   @param[in] Buf              Pointer to input buffer.
     22 
     23   @return                     The UINT16 value obtained from the buffer.
     24 
     25 **/
     26 UINT16
     27 TcpGetUint16 (
     28   IN UINT8 *Buf
     29   )
     30 {
     31   UINT16  Value;
     32   CopyMem (&Value, Buf, sizeof (UINT16));
     33   return NTOHS (Value);
     34 }
     35 
     36 /**
     37   Get a UINT32 value from buffer.
     38 
     39   @param[in] Buf              Pointer to input buffer.
     40 
     41   @return                     The UINT32 value obtained from the buffer.
     42 
     43 **/
     44 UINT32
     45 TcpGetUint32 (
     46   IN UINT8 *Buf
     47   )
     48 {
     49   UINT32  Value;
     50   CopyMem (&Value, Buf, sizeof (UINT32));
     51   return NTOHL (Value);
     52 }
     53 
     54 /**
     55   Put a UINT32 value in buffer.
     56 
     57   @param[out] Buf             Pointer to the buffer.
     58   @param[in] Data             The UINT32 Date to put in the buffer.
     59 
     60 **/
     61 VOID
     62 TcpPutUint32 (
     63      OUT UINT8  *Buf,
     64   IN     UINT32 Data
     65   )
     66 {
     67   Data = HTONL (Data);
     68   CopyMem (Buf, &Data, sizeof (UINT32));
     69 }
     70 
     71 /**
     72   Compute the window scale value according to the given buffer size.
     73 
     74   @param[in]  Tcb Pointer to the TCP_CB of this TCP instance.
     75 
     76   @return         The scale value.
     77 
     78 **/
     79 UINT8
     80 TcpComputeScale (
     81   IN TCP_CB *Tcb
     82   )
     83 {
     84   UINT8   Scale;
     85   UINT32  BufSize;
     86 
     87   ASSERT ((Tcb != NULL) && (Tcb->Sk != NULL));
     88 
     89   BufSize = GET_RCV_BUFFSIZE (Tcb->Sk);
     90 
     91   Scale   = 0;
     92   while ((Scale < TCP_OPTION_MAX_WS) && ((UINT32) (TCP_OPTION_MAX_WIN << Scale) < BufSize)) {
     93 
     94     Scale++;
     95   }
     96 
     97   return Scale;
     98 }
     99 
    100 /**
    101   Build the TCP option in three-way handshake.
    102 
    103   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    104   @param[in]  Nbuf    Pointer to the buffer to store the options.
    105 
    106   @return             The total length of the TCP option field.
    107 
    108 **/
    109 UINT16
    110 TcpSynBuildOption (
    111   IN TCP_CB  *Tcb,
    112   IN NET_BUF *Nbuf
    113   )
    114 {
    115   UINT8   *Data;
    116   UINT16  Len;
    117 
    118   ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
    119 
    120   Len = 0;
    121 
    122   //
    123   // Add a timestamp option if not disabled by the application
    124   // and it is the first SYN segment, or the peer has sent
    125   // us its timestamp.
    126   //
    127   if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_TS) &&
    128       (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
    129         TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_TS))
    130       ) {
    131 
    132     Data = NetbufAllocSpace (
    133              Nbuf,
    134              TCP_OPTION_TS_ALIGNED_LEN,
    135              NET_BUF_HEAD
    136              );
    137 
    138     ASSERT (Data != NULL);
    139     Len += TCP_OPTION_TS_ALIGNED_LEN;
    140 
    141     TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
    142     TcpPutUint32 (Data + 4, mTcpTick);
    143     TcpPutUint32 (Data + 8, 0);
    144   }
    145 
    146   //
    147   // Build window scale option, only when configured
    148   // to send WS option, and either we are doing active
    149   // open or we have received WS option from peer.
    150   //
    151   if (!TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_NO_WS) &&
    152       (!TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_ACK) ||
    153         TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_RCVD_WS))
    154       ) {
    155 
    156     Data = NetbufAllocSpace (
    157              Nbuf,
    158              TCP_OPTION_WS_ALIGNED_LEN,
    159              NET_BUF_HEAD
    160              );
    161 
    162     ASSERT (Data != NULL);
    163 
    164     Len += TCP_OPTION_WS_ALIGNED_LEN;
    165     TcpPutUint32 (Data, TCP_OPTION_WS_FAST | TcpComputeScale (Tcb));
    166   }
    167 
    168   //
    169   // Build the MSS option.
    170   //
    171   Data = NetbufAllocSpace (Nbuf, TCP_OPTION_MSS_LEN, 1);
    172   ASSERT (Data != NULL);
    173 
    174   Len += TCP_OPTION_MSS_LEN;
    175   TcpPutUint32 (Data, TCP_OPTION_MSS_FAST | Tcb->RcvMss);
    176 
    177   return Len;
    178 }
    179 
    180 /**
    181   Build the TCP option in synchronized states.
    182 
    183   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    184   @param[in]  Nbuf    Pointer to the buffer to store the options.
    185 
    186   @return             The total length of the TCP option field.
    187 
    188 **/
    189 UINT16
    190 TcpBuildOption (
    191   IN TCP_CB  *Tcb,
    192   IN NET_BUF *Nbuf
    193   )
    194 {
    195   UINT8   *Data;
    196   UINT16  Len;
    197 
    198   ASSERT ((Tcb != NULL) && (Nbuf != NULL) && (Nbuf->Tcp == NULL));
    199   Len = 0;
    200 
    201   //
    202   // Build the Timestamp option.
    203   //
    204   if (TCP_FLG_ON (Tcb->CtrlFlag, TCP_CTRL_SND_TS) &&
    205       !TCP_FLG_ON (TCPSEG_NETBUF (Nbuf)->Flag, TCP_FLG_RST)
    206       ) {
    207 
    208     Data = NetbufAllocSpace (
    209             Nbuf,
    210             TCP_OPTION_TS_ALIGNED_LEN,
    211             NET_BUF_HEAD
    212             );
    213 
    214     ASSERT (Data != NULL);
    215     Len += TCP_OPTION_TS_ALIGNED_LEN;
    216 
    217     TcpPutUint32 (Data, TCP_OPTION_TS_FAST);
    218     TcpPutUint32 (Data + 4, mTcpTick);
    219     TcpPutUint32 (Data + 8, Tcb->TsRecent);
    220   }
    221 
    222   return Len;
    223 }
    224 
    225 /**
    226   Parse the supported options.
    227 
    228   @param[in]       Tcp     Pointer to the TCP_CB of this TCP instance.
    229   @param[in, out]  Option  Pointer to the TCP_OPTION used to store the
    230                            successfully pasrsed options.
    231 
    232   @retval          0       The options are successfully pasrsed.
    233   @retval          -1      Ilegal option was found.
    234 
    235 **/
    236 INTN
    237 TcpParseOption (
    238   IN     TCP_HEAD   *Tcp,
    239   IN OUT TCP_OPTION *Option
    240   )
    241 {
    242   UINT8 *Head;
    243   UINT8 TotalLen;
    244   UINT8 Cur;
    245   UINT8 Type;
    246   UINT8 Len;
    247 
    248   ASSERT ((Tcp != NULL) && (Option != NULL));
    249 
    250   Option->Flag  = 0;
    251 
    252   TotalLen      = (UINT8) ((Tcp->HeadLen << 2) - sizeof (TCP_HEAD));
    253   if (TotalLen <= 0) {
    254     return 0;
    255   }
    256 
    257   Head = (UINT8 *) (Tcp + 1);
    258 
    259   //
    260   // Fast process of the timestamp option.
    261   //
    262   if ((TotalLen == TCP_OPTION_TS_ALIGNED_LEN) && (TcpGetUint32 (Head) == TCP_OPTION_TS_FAST)) {
    263 
    264     Option->TSVal = TcpGetUint32 (Head + 4);
    265     Option->TSEcr = TcpGetUint32 (Head + 8);
    266     Option->Flag  = TCP_OPTION_RCVD_TS;
    267 
    268     return 0;
    269   }
    270   //
    271   // Slow path to process the options.
    272   //
    273   Cur = 0;
    274 
    275   while (Cur < TotalLen) {
    276     Type = Head[Cur];
    277 
    278     switch (Type) {
    279     case TCP_OPTION_MSS:
    280       Len = Head[Cur + 1];
    281 
    282       if ((Len != TCP_OPTION_MSS_LEN) || (TotalLen - Cur < TCP_OPTION_MSS_LEN)) {
    283 
    284         return -1;
    285       }
    286 
    287       Option->Mss = TcpGetUint16 (&Head[Cur + 2]);
    288       TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_MSS);
    289 
    290       Cur += TCP_OPTION_MSS_LEN;
    291       break;
    292 
    293     case TCP_OPTION_WS:
    294       Len = Head[Cur + 1];
    295 
    296       if ((Len != TCP_OPTION_WS_LEN) || (TotalLen - Cur < TCP_OPTION_WS_LEN)) {
    297 
    298         return -1;
    299       }
    300 
    301       Option->WndScale = (UINT8) MIN (14, Head[Cur + 2]);
    302       TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_WS);
    303 
    304       Cur += TCP_OPTION_WS_LEN;
    305       break;
    306 
    307     case TCP_OPTION_TS:
    308       Len = Head[Cur + 1];
    309 
    310       if ((Len != TCP_OPTION_TS_LEN) || (TotalLen - Cur < TCP_OPTION_TS_LEN)) {
    311 
    312         return -1;
    313       }
    314 
    315       Option->TSVal = TcpGetUint32 (&Head[Cur + 2]);
    316       Option->TSEcr = TcpGetUint32 (&Head[Cur + 6]);
    317       TCP_SET_FLG (Option->Flag, TCP_OPTION_RCVD_TS);
    318 
    319       Cur += TCP_OPTION_TS_LEN;
    320       break;
    321 
    322     case TCP_OPTION_NOP:
    323       Cur++;
    324       break;
    325 
    326     case TCP_OPTION_EOP:
    327       Cur = TotalLen;
    328       break;
    329 
    330     default:
    331       Len = Head[Cur + 1];
    332 
    333       if ((TotalLen - Cur) < Len || Len < 2) {
    334         return -1;
    335       }
    336 
    337       Cur = (UINT8) (Cur + Len);
    338       break;
    339     }
    340 
    341   }
    342 
    343   return 0;
    344 }
    345 
    346 /**
    347   Check the segment against PAWS.
    348 
    349   @param[in]  Tcb     Pointer to the TCP_CB of this TCP instance.
    350   @param[in]  TSVal   The timestamp value.
    351 
    352   @retval     1       The segment passed the PAWS check.
    353   @retval     0       The segment failed to pass the PAWS check.
    354 
    355 **/
    356 UINT32
    357 TcpPawsOK (
    358   IN TCP_CB *Tcb,
    359   IN UINT32 TSVal
    360   )
    361 {
    362   //
    363   // PAWS as defined in RFC1323, buggy...
    364   //
    365   if (TCP_TIME_LT (TSVal, Tcb->TsRecent) &&
    366       TCP_TIME_LT (Tcb->TsRecentAge + TCP_PAWS_24DAY, mTcpTick)
    367       ) {
    368 
    369     return 0;
    370 
    371   }
    372 
    373   return 1;
    374 }
    375