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