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