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